Scala: how is Enumeration not type safe?

enums, scala

Solution

It's semi-safe. That it is type safe is a compiler fiction, so it's easy to break. For example,

trait Parent
class Boy extends Parent { override def toString = "boy" }
class Girl extends Parent { override def toString = "girl" }
def f(g: Girl) = g.toString

scala> f((new Boy).asInstanceOf[Girl])
java.lang.ClassCastException: Boy cannot be cast to Girl
    at .<init>(<console>:15)
    ...

Okay, boys aren't girls.

Now let's try with enumerations:

object Test extends Enumeration { val One, Two = Value }
object Probar extends Enumeration { val Uno, Dos = Value }
def h(tv: Test.Value) = tv.toString

scala> h((Probar.Uno).asInstanceOf[Test.Value])
res0: java.lang.String = Uno

Wait, what?

This fiction leads to other weird behaviors:

def h(pv: Probar.Value) = pv.toString  // Add this to the other h in a :paste

method h:(pv: Probar.Value)java.lang.String and
method h:(tv: Test.Value)java.lang.String at line 9
have same type after erasure: (pv: Enumeration#Value)java.lang.String
           def h(pv: Probar.Value) = pv.toString

Uh, okay, thanks?

And then since the compiler doesn't really understand `Enumeration` as its own construct, it can't help you out in ways you might expect:

scala> def oops(tv: Test.Value) = tv match { case Test.One => "okay" }
oops: (tv: Test.Value)java.lang.String
// No incomplete match warning?  Okay....

scala> oops(Test.Two)
scala.MatchError: Two (of class scala.Enumeration$Val)
    at .oops(<console>:8)
    ...

So if you use it in relatively limited ways exactly as intended, it provides type safety. But it doesn't have the power and robustness of other patterns, like this one:

// In REPL, :paste the next three lines
sealed trait Foo
object Bar extends Foo
object Baz extends Foo

scala> def safe(f: Foo) = f match { case Bar => "okay" }
<console>:9: warning: match is not exhaustive!
missing combination            Baz

        def safe(f: Foo) = f match { case Bar => "okay" }
                           ^

Thanks, compiler!

Problem

I've seen a number of assertions that Scala Enumeration is not type safe. How is it not type safe? It seems type safe in the obvious way in that you can not pass a value of one Enumeration to a different Enumeration. What are the pitfalls or things to avoid with Enumeration?

Original source