Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: how is Enumeration not type safe?

Tags:

enums

scala

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?

like image 822
Rich Oliver Avatar asked Oct 29 '12 20:10

Rich Oliver


People also ask

Is Scala type safe?

While Scala is has a compiler that can help you catch errors, and many call it "type-safe", there is in fact a whole range of ways you can write Scala that provide greater- or lesser- amounts of safety.

What is enumeration in Scala?

An enumeration refers to a group of named constants. Scala provides an abstract class called Enumeration to create and retrieve enumerations.


1 Answers

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!

like image 114
Rex Kerr Avatar answered Sep 28 '22 12:09

Rex Kerr