Hi I am studying the Advanced Scala book, and I have some trouble understading this piece of code from scalaz source:
object Tag {
/** `subst` specialized to `Id`.
*
* @todo According to Miles, @specialized doesn't help here. Maybe manually specialize.
*/
@inline def apply[@specialized A, T](a: A): A @@ T = a.asInstanceOf[A @@ T]
// ...
}
How can it work? a.asInstanceOf[A @@ T]
should fail with ClassCastException shouldn't it?
An example of usage is:
Multiplication(2) |+| Multiplication(3)
In this case a
is an Int how can it be converted to a @@[Int, Multiplication]
(Tagged[Int, Multiplication]
)
Thanks for the help.
This works because of erasure. @@
is a purely type-level construct, meaning it has no runtime representation.
The type A @@ T
is an alias for the type AnyRef{type Tag = T; type Self = A}
. And since Int
can be safely cast to AnyRef
(under the hood this is done via casting a java.lang.Integer
to a java.lang.Object
), this works just fine.
The additional structure {type Tag = T; type Self = A}
only exists at compile-time, so it has been completely erased by the time the JVM does the cast.
Why do this? The purpose of @@
(which I pronounce "qua") is to create a new type from an old one, without incurring a runtime overhead.
If we used, for example, case class Multiplication(value: Int)
, this allows us to treat Multiplication
as distinct from Int
, but it creates an actual Multiplication
object at runtime.
If we used a type alias like type Multiplication = Int
, then there is no runtime overhead. But now Multiplication
is indistinguishable from an Int
, which is not what we want.
The type Int @@ Multiplication
prevents us from using a value of this type directly as an Int
, even though it really is just an Int
at runtime.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With