Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Differences between scala and java enumerations

I read an answer on SO where someone said that scala enumerations are useless, and you should just use java enumerations instead if you really need too.

Although I have used java enumerations before, I can't say I fully understand them as I don't code in java during my day job.

Can someone explain the differences between scala and java enumerations, and where exactly the shortcomings in scala enums are?

like image 282
public static Avatar asked Aug 29 '14 15:08

public static


1 Answers

The main advantage of Scala's Enumeration is the regularity of the syntax.

If you want to add behavior to elements of your enum, just extend its Val class.

Odersky likes them for their simplest use case as named int-valued constants. And he just promised on the mailing list, for the first time, that improved support is on the horizon.

But I recently used them to replace a list of strings, since the set of values is a bit set, nicer than a set of strings for look-up.

Instead of

val stuff = List("foo", "bar", "baz")

object stuff extends Enumeration { val foo, bar, baz = Value }

or

scala> object stuff extends Enumeration { val foo, bar, baz = Value }
defined object stuff

scala> val junk = new Enumeration { val foo, bar, baz = Value }
junk: Enumeration{val foo: this.Value; val bar: this.Value; val baz: this.Value} = 1

scala> stuff.values contains junk.foo
<console>:10: error: type mismatch;
 found   : junk.Value
 required: stuff.Value
              stuff.values contains junk.foo
                                         ^

Behavior:

scala> trait Alias { def alias: String }
defined trait Alias

scala> object aliased extends Enumeration {
     | class Aliased extends Val with Alias {
     |   def alias = toString.permutations.drop(1).next }
     | val foo, bar, baz = new Aliased }
defined object aliased

scala> abstract class X { type D <: Enumeration
     | def f(x: D#Value) = x match { case a: Alias => a.alias
     |   case _ => x.toString } }
defined class X

scala> class Y extends X { type D = aliased.type }
defined class Y

scala> new Y().f(aliased.bar)
res1: String = bra

scala> new Y().f(stuff.foo)
<console>:13: error: type mismatch;
 found   : stuff.Value
 required: aliased.Value
              new Y().f(stuff.foo)
                              ^

scala> new X { type D = junk.type }.f(junk.foo)
warning: there was one feature warning; re-run with -feature for details
res4: String = foo

ValueSet is a bit set:

scala> stuff.values contains aliased.bar
<console>:11: error: type mismatch;
 found   : aliased.Aliased
 required: stuff.Value
              stuff.values contains aliased.bar
                                            ^

scala> stuff.foo + aliased.bar
<console>:11: error: type mismatch;
 found   : aliased.Aliased
 required: stuff.Value
              stuff.foo + aliased.bar
                                  ^

scala> stuff.foo + stuff.bar
res8: stuff.ValueSet = stuff.ValueSet(foo, bar)

Other stuff that seems to work in today's Scala:

scala> def f[E <: Enumeration](e: E)(v: e.Value) = e.ValueSet.empty + v
f: [E <: Enumeration](e: E)(v: e.Value)e.ValueSet

scala> f(stuff)(stuff.foo)
res14: stuff.ValueSet = stuff.ValueSet(foo)

scala> def g[E <: Enumeration](e: E)(a: Any) = a match { case _: e.Value => true case _ => false }
g: [E <: Enumeration](e: E)(a: Any)Boolean

scala> g(stuff)(stuff.foo)
res15: Boolean = true

scala> g(stuff)(junk.foo)    // checking outer pointers
warning: there was one feature warning; re-run with -feature for details
res16: Boolean = false

scala> g(stuff)(aliased.foo)
res17: Boolean = false

It looks like Scala is not entirely friendly to Java enums:

scala> Thread.State.NEW.ordinal
[snip]
scala.reflect.internal.FatalError: 
  Unknown type: <notype>(NEW), <notype> [class scala.reflect.internal.Types$UniqueConstantType, class scala.reflect.internal.Types$NoType$] TypeRef? false
     while compiling: <console>
        during phase: icode
     library version: version 2.11.2
    compiler version: version 2.11.2
  reconstructed args: 

  last tree to typer: Apply(method ordinal)
       tree position: line 8 of <console>
            tree tpe: Int
              symbol: final method ordinal in class Enum
   symbol definition: final def ordinal(): Int (a MethodSymbol)
      symbol package: java.lang
       symbol owners: method ordinal -> class Enum
           call site: constructor $read$$iw$$iw in package $line4
like image 163
som-snytt Avatar answered Oct 22 '22 02:10

som-snytt