fwilliams
fwilliams

Reputation: 47

Creating an instance from a type parameter in scala

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

Answers (1)

dhg
dhg

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

Related Questions