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?
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With