Skip to content

Instantly share code, notes, and snippets.

@mbloms
Last active November 19, 2020 21:31
Show Gist options
  • Save mbloms/f1ef10a48691762fe1be60cc1ebfda9d to your computer and use it in GitHub Desktop.
Save mbloms/f1ef10a48691762fe1be60cc1ebfda9d to your computer and use it in GitHub Desktop.

The precence of the asInstanceOf as a method on Any is something which has annoyed me since I first understood how it works. As a Scala beginner coming from Java googling how to do type casts in Scala what you will get is "in Scala it's asInstanceOf". So most people explaining Scala to a Java developer would say that x.asInstanceOf[C] is equivalent to (C) x.

Looking at the rules for asInstanceOf on primitive types also indicates that this could have been the purpose in the beginning.

Now, every time there is a proposal for a new interesting feature in the type system, at some point inevitably someone will say "But what about x.asInstanceOf?". To which the answer is always "asInstanceOf is a universal escape hatch, which comes with no guarantees."

Any interesting research concerning Scala's type system must be done in a subset of Scala without asInstanceOf since of course otherwise nothing can actually be proved.

It's clear to me that people perceive asInstanceOf as one of two things:

  • The equivalent of Java's cast expression
  • A Jedi mind trick that can be used to make the compiler believe anything

Although it's important to point out that Java's cast expression is absolutely not type safe, it comes with some checks and it's not as easy to abuse as Scala's asInstanceOf.

I think separating these two conflicting roles would improve the language.

I propose a new method that will replace the role of asInstanceOf as an escape hatch and that must be imported explicitly. It could look something like this:

package scala
package misc

object Unsafe {
  /** Coerce any object to type T.
    * The compiler must make sure x and T has the same internal representation.
    */
  def unsafeCoerce[T](x: Any): T
}

The use of asInstanceOf is restricted

I also think the special meaning of using asInstanceOf to convert between number types is unfortunate since it leads to weirdness things like this:

scala> def cast[T,R](x: T): R = x.asInstanceOf[R]                                                                                                                                                                                           
def cast[T, R](x: T): R

scala> val xs = List(1,2,3,4,5)                                                                                                                                                                                                             
val xs: List[Int] = List(1, 2, 3, 4, 5)

scala> xs.map(_.asInstanceOf[Double])                                                                                                                                                                                                       
val res0: List[Double] = List(1.0, 2.0, 3.0, 4.0, 5.0)

scala> xs.map(cast[Int,Double])                                                                                                                                                                                                             
java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.Double (java.lang.Integer and java.lang.Double are in module java.base of loader 'bootstrap')

I think it's tricky to handle null.asInstanceOf[T].

In the special case T >: Null is trivial.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment