Reputation: 63
I am experimenting with context bounds in scala and I don't find a way to make the either of these two functions typecheck:
abstract class Expr
case class Val[T: Numeric](v: T) extends Expr
case object Other extends Expr
val e1 = Val(1)
val e2 = Val(2)
def addExp1(e1: Expr, e2: Expr): Expr = (e1, e2) match {
case (Val(v1), Val(v2)) => Val(v1+v2)
case _ => Other
}
def addExp2[T: Numeric](e1: Expr, e2: Expr): Expr = (e1, e2) match {
case (Val(v1: T), Val(v2: T)) => Val(v1+v2)
case _ => Other
}
In the case of addExp1, I can understand that the compiler has no information at the function definition point to know that the arguments of Val are Numeric and thus have a + method. It just matches Any as the type of v1.
In the case of addExp2, how can I force the bound in the pattern? The type is "erased"...T annotation is eliminated by erasure...
What I would dream of having is a single point to put the bound, ideally at the definition of the Val class.
Upvotes: 3
Views: 575
Reputation: 1892
One way to avoid losing the parameterised type of Val is to have Expr take a type parameter as well.
abstract class Expr[T]
case class Val[T: Numeric](v: T) extends Expr[T]
case object Other extends Expr[Nothing]
val e1 = Val(1)
val e2 = Val(2)
def addExp2[T: Numeric](e1: Expr[T], e2: Expr[T]): Expr[_ <: T] = (e1, e2) match {
case (Val(v1), Val(v2)) => Val(implicitly[Numeric[T]].plus(v1, v2))
case _ => Other
}
addExp2[Int](e1, e2)
This compiles with no warnings.
Now all we need is a way to specify a default type of Nothing
for the type parameter of Expr :).
Upvotes: 3
Reputation: 5712
The problem is that when you pattern match, the two instances of Val
can have different type parameters, say Val[T1]
and Val[T2]
.
You can fix that as suggested by @rjsvaljean, and add import Numeric.Implicits._
to use the nice operator notation.
Upvotes: 3