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