Sometimes i get bitten by type erasure without an obvious (or elegant) way out. Very often this boils down to not being able to separate
X[B] in one way or an other. In Scala 2 you could call
TypeTag to the rescue, but Scala 3 only provides
ClassTag which is not powerful enough. For example:
class X[T <: A|B] :
def sideEffect(t: T): Unit = println(t.toString)
val a = new A
val b = new B
def test[T <: A|B : ClassTag](x: X[T]): Unit = x match
case xc: X[A] => xc.sideEffect(a)
case xc: X[B] => xc.sideEffect(b)
case _ => println("not found")
val xa = new X[A]()
val xb = new X[B]()
still results (scastie) in the warning:
the type test for X[A] cannot be checked at runtime
at the matching lines.
One solution (scastie) could be to add a
dummy: T field to
X[T] and test on that. Works, but no so elegant, and often not applicable.
Are there other ways in Scala 3 to solve this? I found the remark from Prof. Odersky about
quoted.Type in a conversation about reflection, but have no idea how to use that. The online doc about this subject does not seem updated.
From what I understand its seems like you can use quotes (macros). As per the previous link, you can match on a specific type via quotes or use
Type.of directly. Don’t forget to add this
using explicitly or via a type parameter context.
I have not checked, but you can look at some examples to see if one can provides some “inspiration”.
BTW: I think an alternative way, that still uses additional parameters, is to add a 2nd
using parameter and request evidence of the type via
=:= . At the call site you need not add this implicit parameter.
you can use Izumi reflect which is “good enough” representation of a type tag for the case you present here
Just for the kicks, a very verbose but reflection-free/type-only take (perhaps a variant of the alternative approach @hmf suggested?).
sealed trait Disp[T <: A | B]:
def disp(xc: X[T]): Unit
class SubDisp[T <: A | B](t: T) extends Disp[T]:
def disp(xc: X[T]): Unit = xc.sideEffect(t)
given Disp[A] = new SubDisp(a)
given Disp[B] = new SubDisp(b)
given Disp[A | B] with
def disp(xc: X[A | B]): Unit = println("not found")
def test[T <: A | B : Disp](x: X[T]): Unit = summon[Disp[T]].disp(x)
Thanks @hmf , @bishabosha and @sangamon for the tips. Not exactly what i had hoped for, (namely something syntactically close to the original intent) but i guess that’s the price to pay for benefits of type erasure. Also, i am a bit reluctant to pull in a framework just for one or two cases.