Reputation: 47
I am writing a small calculator in scala as a learning exercise.
I have a BinExpr[T]
class which represents a binary expression of type T.
The full signature is as follows:
abstract sealed class Expr()
abstract sealed class BinExpr[T <: BinExpr[T]](val v1: Expr, val v2: Expr) extends Expr
I have a replace function that replaces a variable (a string symbol in an expression) with a literal.
def replace(e: Expr, s: Var, t: Lit): Expr = e match {
case v: Var if v.symbol == s.symbol => t
case v: Var => v
case l: Lit => l
case b: BinExpr[T] => new T(replace(b.v1, s, t), replace(b.v2, s, t))
}
This gives me the following errors:
calculator.scala:31: error: not found: type T
case b: BinExpr[T] => new T(replace(b.v1, s, t), replace(b.v2, s, t))
^
calculator.scala:31: error: not found: type T
case b: BinExpr[T] => new T(replace(b.v1, s, t), replace(b.v2, s, t))
I understand that type erasure causes the T
not to be available at runtime. That said, BinExpr[T]
is a sealed class. Therefore, T
can only be one of a small number of types, which are known at compile time. It seems to me that this case should just be expanded to capture those values of T
. Clearly this is not the case. Is there a way I can achieve this?
Upvotes: 0
Views: 151
Reputation: 52681
How about putting a factory method on BinExpr
so that each subclass knows how to instantiate itself, given two new parameters. Here's a simplified example:
trait A {
def make(a: Int, b: Int): A
}
class B(x: Int, y: Int) extends A {
def make(a: Int, b: Int) = new B(x, y)
}
class C(x: Int, y: Int) extends A {
def make(a: Int, b: Int) = new C(x, y)
}
def f(x: A): A = x match {
case a: A => a.make(1, 2)
}
val b = f(new B(5, 6))
val c = f(new C(5, 6))
Upvotes: 2