简体   繁体   中英

Design of Scala's class hierarchy. Constructor parameter vs member

I'm having problems designing the a class hierarchy in scala for a compiler project. The hierarchy looks as follows:

abstract class TACInstr(index:Int)

case class TAC_Label(label: String,index : Int) extends TACInstr(index)
case class TAC_Jump(label: TAC_Label,index : Int) extends TACInstr(index)
...

Here index is a variable that represents the order number of the instruction in some listing. It is important that I cannot declare this variable to be immutable at least for the TAC_Label subclass because it is not always predictable in my code what should be its index when it is declared.

Later on I'm using this index value in the following definition:

  def getBlock(i : TACInstr) : BasicBlock = 
blocks.find(b => b.instr.index == i.index).get

So basically I'm comparing the equality of two indexes of different instructions. This gives the following error:

Cannot resolve symbol index

because apparently in this way index is private to the classes definitions

My approaches

I tried to declare the hierarchy as follows:

abstract class TACInstr(var index:Int)

case class TAC_Label(label: String,override var index : Int) extends TACInstr(index)
case class TAC_Jump(label: TAC_Label,override var index : Int) extends TACInstr(index)
...

But I'm obtaining the following error type:

Error:... overriding variable index in class TACInstr of type Int;
 variable index cannot override a mutable variable

Are there any elegant solutions to this problem? Something better than declaring index as a member?

The main problem is that you are trying to override a field. The examples below solve the problem:

// index is public
abstract class TACInstr(var index:Int)

// label is public, i is private
class TAC_Label(val label: String, i: Int) extends TACInstr(i)
class TAC_Jump(val label: TAC_Label, i: Int) extends TACInstr(i)

val l = new TAC_Label("l", 0)
println(l.index)

Now with traits

trait TACInstr { var index:Int }

case class TAC_Label(label: String, var index: Int) extends TACInstr
case class TAC_Jump(label: TAC_Label, var index: Int) extends TACInstr

val l = TAC_Label("l", 0)
println(l.index)

More scala way

trait TACInstr { val index:Int }

// label is public, i is private
case class TACLabel(label: String, val index: Int) extends TACInstr
case class TACJump(label: TACLabel, val index: Int) extends TACInstr {
    def withLabelIndex(newIndex: Int): TACJump = this.copy(label = label.copy(index = newIndex))
}

val jump = TACJump(TACLabel("l", 1), 2)
val changed = jump.withLabelIndex(3)
println(changed)

This is not the way of writing things in scala. Many smells are: abstract class, var, parent fields. Code in scala not in its design way will only make it hard.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM