Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scalaz `Tag.apply`: How does it work?

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.

like image 886
Filippo De Luca Avatar asked Dec 14 '22 14:12

Filippo De Luca


1 Answers

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.

like image 97
Apocalisp Avatar answered Jan 05 '23 15:01

Apocalisp