Reputation: 107
I have an Operator
abstract class:
abstract class Operator[T, U] {
def setParent(op: Operator[T, U]): Unit
def newOp(): Operator[Byte, String] = {
val newOperator = new NewOperator[Byte, String]
newOperator.setParent(this)
newOperator
}
}
and another NewOperator
class
class NewOperator[T, U] extends Operator[T, U] {
var parent: Operator[T,U] = null
def setParent(op: Operator[T, U]): Unit = {this.parent = op}
}
Now, in the second line in newOp()
method in class Operator
, I get an error
newOperator.setParent(this)
^
which says: Type mismatch: expected: Operator[Byte, String], actual: Operator[T, U]
.
Is the only way to resolve this, is to add .instanceOf[Operator[Byte, String]]
to this
?
newOperator.setParent(this.instanceOf[Operator[Byte, String]])
Upvotes: 1
Views: 104
Reputation: 396
Instead of doing like this
newOperator.setParent(this) in abstract class operator you can do something like this
newOperator.setParent(newOperator)
This will solve your problem
Upvotes: 0
Reputation: 22374
Your current solution restricts all your Operator[Byte, String] to have Operator[Byte, String] parent type (and you will found it only in runtime if you use asInstanceOf
).
In general case if parent/child generic type may be different use:
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Operator[T, U, P <: Operator[_, _, _]] {
var parent: P = null.asInstanceOf[P]
def setParent(op: P): Unit = {this.parent = op}
def newOp[TT, UU]() = {
val newOperator = new Operator[TT, UU, Operator[T, U, P]]()
newOperator.setParent(this)
newOperator
}
}
// Exiting paste mode, now interpreting.
defined class Operator
scala> new Operator[Byte, String, Null]
res19: Operator[Byte,String,Null] = Operator@5470e2f4
scala> res19.newOp[Int, String]
res20: Operator[Int,String,Operator[Byte,String,Null]] = Operator@729c1e43
scala> res20.parent
res21: Operator[Byte,String,Null] = Operator@5470e2f4
You may move newOp
to some subclass and make Operator a trait, if you need to have some specific state/methods for your Operator.
Or you can use type classes for operator specific operations:
scala> new Operator[Byte, String, Null]
res23: Operator[Byte,String,Null] = Operator@728b49e2
scala> implicit class ByteOperator(o: Operator[Byte, String, _]) {
| def hello = "hello" //here you can access some members of Operator
| }
defined class ByteOperator
scala> res23.hello
res24: String = hello
If you really need children having same generic as parents:
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Operator[T, U] {
var parent: Operator[T, U] = null
def newInstance: Operator[T, U] = new Operator[T, U]
def newOp: Operator[T, U] = {
val newOperator = newInstance
newOperator.setParent(this)
newOperator
}
def setParent(op: Operator[T, U]): Unit = {this.parent = op}
}
// Exiting paste mode, now interpreting.
defined class Operator
scala> new Operator[Byte, String]
res15: Operator[Byte,String] = Operator@4e6ea769
scala> res15.newOp
res16: Operator[Byte,String] = Operator@c774157
scala> res16.parent
res17: Operator[Byte,String] = Operator@4e6ea769
If you just need to model some AST (Abstract Syntax Tree), case classess may be a good solution:
trait Expression[T] {
def v: T
}
case class Value[T](v: T) extends Expression[T]
case class Plus[T1, T2](a: Expression[T1], b: Expression[T2])(implicit wrap: T1 => Arithmetic[T1, T2]) extends Expression[T1] {
def v = wrap(a.v) ++ b.v
}
abstract class Arithmetic[T1, T2](v: T1) {
def ++ (v: T2): T1
}
implicit class ArithmeticInt(val v: Int) extends Arithmetic[Int, Int](v) {
def ++ (v2: Int) = v + v2
}
implicit class ArithmeticIntDouble(val v: Int) extends Arithmetic[Int, Double](v) {
def ++ (v2: Double) = (v.toDouble + v2).toInt
}
scala> Plus(Value(5.0), Value(11.0)).v
res57: Value[Double] = Value(16.0)
scala> Plus(Value(5), Value(11.0)).v
res67: Int = 16
scala> Plus(Value(5), Value(6)).v
res68: Int = 11
scala> Plus(Value(5.0), Value(6)).v
<console>:60: error: No implicit view available from Double => Arithmetic[Double,Int].
Plus(Value(5.0), Value(6)).v
^
Upvotes: 1
Reputation: 3622
why not make the method newOp
generic?
abstract class Operator[T, U] {
def setParent(op: Operator[T, U]): Unit
def newOp(): Operator[T, U] = {
val newOperator = new NewOperator[T, U]
newOperator.setParent(this)
newOperator
}
}
class NewOperator[T, U] extends Operator[T, U] {
var parent: Operator[T,U] = null
def setParent(op: Operator[T, U]): Unit = {this.parent = op}
}
val op = new NewOperator[Byte, String]().newOp
Upvotes: 1