This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Scala Enumeration

17 replies
G J
Joined: 2011-12-16,
User offline. Last seen 42 years 45 weeks ago.

Can someone explain why IDLE is always printed as 'x'?

object State extends Enumeration {
val IDLE, STARTED = Value
var x = IDLE
}

scala> State.x
res16: State.Value = x // okay...

scala> State.x = State.STARTED
State.x: State.Value = STARTED

scala> State.x
res17: State.Value = STARTED // expected.

scala> State.x = State.IDLE
State.x: State.Value = x // huh?

scala> State.x
res18: State.Value = x // what?

Thanks.

G J
Joined: 2011-12-16,
User offline. Last seen 42 years 45 weeks ago.
Re: Scala Enumeration

To add;

State.withName("IDLE")

generates an exception, whereas State.withName("STARTED") doesn't.

Thanks.

On Feb 12, 9:17 pm, G J wrote:
> Can someone explain why IDLE is always printed as 'x'?
>
> object State extends Enumeration {
>     val IDLE, STARTED = Value
>     var x = IDLE
>
> }
>
> scala> State.x
> res16: State.Value = x                           // okay...
>
> scala> State.x = State.STARTED
> State.x: State.Value = STARTED
>
> scala> State.x
> res17: State.Value = STARTED             // expected.
>
> scala> State.x = State.IDLE
> State.x: State.Value = x                           // huh?
>
> scala> State.x
> res18: State.Value = x                            // what?
>
> Thanks.

Stefan Zeiger
Joined: 2008-12-21,
User offline. Last seen 27 weeks 3 days ago.
Re: Scala Enumeration

On 2012-02-13 3:17, G J wrote:
> Can someone explain why IDLE is always printed as 'x'?
>
> object State extends Enumeration {
> val IDLE, STARTED = Value
> var x = IDLE
> }

Enumeration uses some reflection hack to discover the names of the
values (if you don't specify them explicitly). There's a field named "x"
in your enumeration object, so the value is named "x". Apparently the
last field wins.

-sz

odersky
Joined: 2008-07-29,
User offline. Last seen 45 weeks 6 days ago.
Re: Scala Enumeration

On Mon, Feb 13, 2012 at 10:42 AM, Stefan Zeiger wrote:
> On 2012-02-13 3:17, G J wrote:
>>
>> Can someone explain why IDLE is always printed as 'x'?
>>
>> object State extends Enumeration {
>>     val IDLE, STARTED = Value
>>     var x = IDLE
>> }
>
>
> Enumeration uses some reflection hack to discover the names of the values
> (if you don't specify them explicitly). There's a field named "x" in your
> enumeration object, so the value is named "x". Apparently the last field
> wins.

Yes, that's a bug. Please create a ticket!

Thanks

Jan Vanek
Joined: 2011-08-23,
User offline. Last seen 42 years 45 weeks ago.
Re: Re: Scala Enumeration
A possible fix to Enumeration's method populateNameMap()
  private def populateNameMap() {    val fields = getClass.getDeclaredFields    def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
    // The list of possible Value methods: 0-args which return a conforming type    val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&                                                   classOf[Value].isAssignableFrom(m.getReturnType) &&                                                    m.getDeclaringClass != classOf[Enumeration] &&                                                   isValDef(m))    val setters = getClass.getMethods filter (m => m.getParameterTypes.length == 1 &&                                                    classOf[Value].isAssignableFrom(m.getParameterTypes.apply(0)) &&                                                   classOf[Unit] == m.getReturnType &&                                                    m.getDeclaringClass != classOf[Enumeration] &&                                                   m.getName.endsWith("_$eq"))    methods foreach { m =>       val name = m.getName      if (!setters.exists(m => m.getName == name + "_$eq")) {        // invoke method to obtain actual `Value` instance        val value = m.invoke(this).asInstanceOf[Value]         // verify that outer points to the correct Enumeration: ticket #3616.        if (value.outerEnum eq thisenum) {          val id = Int.unbox(classOf[Val] getMethod "id" invoke value)           nmap += ((id, name))        }      }    }  }
It would still not solve following:
object State extends Enumeration {   val IS_FIRST = Value   val WHICH_ONE = IS_FIRST }
With regards,Jan

On Mon, Feb 13, 2012 at 3:31 AM, G J <odaym2@gmail.com> wrote:
To add;

  State.withName("IDLE")

generates an exception, whereas State.withName("STARTED") doesn't.

Thanks.

On Feb 12, 9:17 pm, G J <oda...@gmail.com> wrote:
> Can someone explain why IDLE is always printed as 'x'?
>
> object State extends Enumeration {
>     val IDLE, STARTED = Value
>     var x = IDLE
>
> }
>
> scala> State.x
> res16: State.Value = x                           // okay...
>
> scala> State.x = State.STARTED
> State.x: State.Value = STARTED
>
> scala> State.x
> res17: State.Value = STARTED             // expected.
>
> scala> State.x = State.IDLE
> State.x: State.Value = x                           // huh?
>
> scala> State.x
> res18: State.Value = x                            // what?
>
> Thanks.

tolsen77
Joined: 2008-10-08,
User offline. Last seen 1 year 38 weeks ago.
Re: Re: Scala Enumeration
I reget contributing life-support to Enumeration. You should too! :) Anyway, anything useful in the new reflection api that could be used in a rewrite?

On 13 February 2012 12:02, Jan Vanek <j3vanek@googlemail.com> wrote:
A possible fix to Enumeration's method populateNameMap()
  private def populateNameMap() {     val fields = getClass.getDeclaredFields    def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
    // The list of possible Value methods: 0-args which return a conforming type    val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&                                                   classOf[Value].isAssignableFrom(m.getReturnType) &&                                                    m.getDeclaringClass != classOf[Enumeration] &&                                                   isValDef(m))    val setters = getClass.getMethods filter (m => m.getParameterTypes.length == 1 &&                                                    classOf[Value].isAssignableFrom(m.getParameterTypes.apply(0)) &&                                                   classOf[Unit] == m.getReturnType &&                                                    m.getDeclaringClass != classOf[Enumeration] &&                                                   m.getName.endsWith("_$eq"))     methods foreach { m =>       val name = m.getName      if (!setters.exists(m => m.getName == name + "_$eq")) {        // invoke method to obtain actual `Value` instance        val value = m.invoke(this).asInstanceOf[Value]         // verify that outer points to the correct Enumeration: ticket #3616.        if (value.outerEnum eq thisenum) {          val id = Int.unbox(classOf[Val] getMethod "id" invoke value)           nmap += ((id, name))        }      }    }  }
It would still not solve following:
object State extends Enumeration {   val IS_FIRST = Value   val WHICH_ONE = IS_FIRST }
With regards,Jan

On Mon, Feb 13, 2012 at 3:31 AM, G J <odaym2@gmail.com> wrote:
To add;

  State.withName("IDLE")

generates an exception, whereas State.withName("STARTED") doesn't.

Thanks.

On Feb 12, 9:17 pm, G J <oda...@gmail.com> wrote:
> Can someone explain why IDLE is always printed as 'x'?
>
> object State extends Enumeration {
>     val IDLE, STARTED = Value
>     var x = IDLE
>
> }
>
> scala> State.x
> res16: State.Value = x                           // okay...
>
> scala> State.x = State.STARTED
> State.x: State.Value = STARTED
>
> scala> State.x
> res17: State.Value = STARTED             // expected.
>
> scala> State.x = State.IDLE
> State.x: State.Value = x                           // huh?
>
> scala> State.x
> res18: State.Value = x                            // what?
>
> Thanks.


Stefan Zeiger
Joined: 2008-12-21,
User offline. Last seen 27 weeks 3 days ago.
Re: Scala Enumeration

On 2012-02-13 10:42, Stefan Zeiger wrote:
> On 2012-02-13 3:17, G J wrote:
>> Can someone explain why IDLE is always printed as 'x'?
>>
>> object State extends Enumeration {
>> val IDLE, STARTED = Value
>> var x = IDLE
>> }
>
> Enumeration uses some reflection hack to discover the names of the
> values (if you don't specify them explicitly). There's a field named
> "x" in your enumeration object, so the value is named "x". Apparently
> the last field wins.

That's a great explanation I came up with, don't you think? There's just
one flaw: It's wrong! I can't reproduce this on either 2.9.1 or some
nightly build from 2 weeks ago (long after my Enumeration changes were
merged into master). In both versions, the enum value is named IDLE, not x.

So, on which version is this supposed to happen? There are a couple of
very similar bugs in JIRA
(https://issues.scala-lang.org/browse/SI-5211), some of them already closed.

-sz

G J
Joined: 2011-12-16,
User offline. Last seen 42 years 45 weeks ago.
Re: Scala Enumeration

This happens in Scala version 2.9.1.final (OpenJDK 64-Bit Server VM,
Java 1.7.0_b147-icedtea).

Thanks.

On Feb 13, 11:44 am, Stefan Zeiger wrote:
> On 2012-02-13 10:42, Stefan Zeiger wrote:
>
> > On 2012-02-13 3:17, G J wrote:
> >> Can someone explain why IDLE is always printed as 'x'?
>
> >> object State extends Enumeration {
> >>      val IDLE, STARTED = Value
> >>      var x = IDLE
> >> }
>
> > Enumeration uses some reflection hack to discover the names of the
> > values (if you don't specify them explicitly). There's a field named
> > "x" in your enumeration object, so the value is named "x". Apparently
> > the last field wins.
>
> That's a great explanation I came up with, don't you think? There's just
> one flaw: It's wrong! I can't reproduce this on either 2.9.1 or some
> nightly build from 2 weeks ago (long after my Enumeration changes were
> merged into master). In both versions, the enum value is named IDLE, not x.
>
> So, on which version is this supposed to happen? There are a couple of
> very similar bugs in JIRA
> (https://issues.scala-lang.org/browse/SI-5211), some of them already closed.
>
> -sz

Stefan Zeiger
Joined: 2008-12-21,
User offline. Last seen 27 weeks 3 days ago.
Re: Re: Scala Enumeration

On 2012-02-14 11:33, G J wrote:
> This happens in Scala version 2.9.1.final (OpenJDK 64-Bit Server VM,
> Java 1.7.0_b147-icedtea).

Except for OpenJDK, that's what I am using, too:

Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM,
Java 1.7.0).
Type in expressions to have them evaluated.
Type :help for more information.

scala> object State extends Enumeration {
| val IDLE, STARTED = Value
| var x = IDLE
| }
defined module State

scala> State.x
res0: State.Value = IDLE

scala> State.IDLE
res1: State.Value = IDLE

-sz

marius
Joined: 2008-08-31,
User offline. Last seen 3 years 19 weeks ago.
Re: Re: Scala Enumeration
Wouldn't it be possible that an built-in compiler plugin to figure out the enumeration content instead of using reflection ?

Thanks,
Marius

On Mon, Feb 13, 2012 at 1:02 PM, Jan Vanek <j3vanek@googlemail.com> wrote:
A possible fix to Enumeration's method populateNameMap()
  private def populateNameMap() {     val fields = getClass.getDeclaredFields    def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
    // The list of possible Value methods: 0-args which return a conforming type    val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&                                                   classOf[Value].isAssignableFrom(m.getReturnType) &&                                                    m.getDeclaringClass != classOf[Enumeration] &&                                                   isValDef(m))    val setters = getClass.getMethods filter (m => m.getParameterTypes.length == 1 &&                                                    classOf[Value].isAssignableFrom(m.getParameterTypes.apply(0)) &&                                                   classOf[Unit] == m.getReturnType &&                                                    m.getDeclaringClass != classOf[Enumeration] &&                                                   m.getName.endsWith("_$eq"))     methods foreach { m =>       val name = m.getName      if (!setters.exists(m => m.getName == name + "_$eq")) {        // invoke method to obtain actual `Value` instance        val value = m.invoke(this).asInstanceOf[Value]         // verify that outer points to the correct Enumeration: ticket #3616.        if (value.outerEnum eq thisenum) {          val id = Int.unbox(classOf[Val] getMethod "id" invoke value)           nmap += ((id, name))        }      }    }  }
It would still not solve following:
object State extends Enumeration {   val IS_FIRST = Value   val WHICH_ONE = IS_FIRST }
With regards,Jan

On Mon, Feb 13, 2012 at 3:31 AM, G J <odaym2@gmail.com> wrote:
To add;

  State.withName("IDLE")

generates an exception, whereas State.withName("STARTED") doesn't.

Thanks.

On Feb 12, 9:17 pm, G J <oda...@gmail.com> wrote:
> Can someone explain why IDLE is always printed as 'x'?
>
> object State extends Enumeration {
>     val IDLE, STARTED = Value
>     var x = IDLE
>
> }
>
> scala> State.x
> res16: State.Value = x                           // okay...
>
> scala> State.x = State.STARTED
> State.x: State.Value = STARTED
>
> scala> State.x
> res17: State.Value = STARTED             // expected.
>
> scala> State.x = State.IDLE
> State.x: State.Value = x                           // huh?
>
> scala> State.x
> res18: State.Value = x                            // what?
>
> Thanks.


G J
Joined: 2011-12-16,
User offline. Last seen 42 years 45 weeks ago.
Re: Scala Enumeration

Absolutely amazing! So much for Java portability.

As clear as day light, it fails under OpenJDK [or in my version].
Anyone have a deeper understanding of the differences? Which one is
right....?

Thanks.

On Feb 14, 5:55 am, Stefan Zeiger wrote:
> On 2012-02-14 11:33, G J wrote:
>
> > This happens in Scala version 2.9.1.final (OpenJDK 64-Bit Server VM,
> > Java 1.7.0_b147-icedtea).
>
> Except for OpenJDK, that's what I am using, too:
>
> Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM,
> Java 1.7.0).
> Type in expressions to have them evaluated.
> Type :help for more information.
>
> scala> object State extends Enumeration {
>       |   val IDLE, STARTED = Value
>       |   var x = IDLE
>       | }
> defined module State
>
> scala> State.x
> res0: State.Value = IDLE
>
> scala> State.IDLE
> res1: State.Value = IDLE
>
> -sz

Simon Ochsenreither
Joined: 2011-07-17,
User offline. Last seen 42 years 45 weeks ago.
Re: Re: Scala Enumeration
I would propose a compiler plugin to figure out if Enumerations is broken. For simplicity, it could be implemented by ignoring the input arguments and always returning true.
Jason Zaugg
Joined: 2009-05-18,
User offline. Last seen 38 weeks 5 days ago.
Re: Re: Scala Enumeration

On Tue, Feb 14, 2012 at 12:46 PM, G J wrote:
>
> Absolutely amazing! So much for Java portability.
>
> As clear as day light, it fails under OpenJDK [or in my version].
> Anyone have a deeper understanding of the differences?  Which one is
> right....?

"The elements in the array returned are not sorted and are not in any
particular order"

http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#getMethods()

-jason

Jan Vanek
Joined: 2011-08-23,
User offline. Last seen 42 years 45 weeks ago.
Re: Re: Scala Enumeration
object State extends Enumeration {   val IDLE = Value   val /*or var*/ N: Value = null } def main(args: Array[String]) { println(State.IDLE) }
produces:Exception in thread "main" java.lang.NullPointerException at scala.Enumeration$$anonfun$scala$Enumeration$$populateNameMap$1.apply(Enumeration.scala:173) at scala.Enumeration$$anonfun$scala$Enumeration$$populateNameMap$1.apply(Enumeration.scala:168) at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:34) at scala.collection.mutable.ArrayOps.foreach(ArrayOps.scala:38) at scala.Enumeration.scala$Enumeration$$populateNameMap(Enumeration.scala:168)
Very minor and can easily be fixed: old:    if (value.outerEnum eq thisenum) {new:    if (value != null && (value.outerEnum eq thisenum)) {
With regards,Jan
DaveScala
Joined: 2011-03-18,
User offline. Last seen 1 year 21 weeks ago.
Re: Scala Enumeration

I can confirm:

C:\Users\Dave>scala
Welcome to Scala version 2.10.0-M1 (Java HotSpot(TM) Client VM, Java
1.6.0_30).
Type in expressions to have them evaluated.
Type :help for more information.

scala> object State extends Enumeration {
| var IDLE, STARTED = Value
| var x = IDLE
| }
defined module State

scala> State.x
res0: State.Value = x

scala> State.x = State.STARTED
State.x: State.Value = STARTED

scala> State.x
res1: State.Value = STARTED

scala> State.x = State.IDLE
State.x: State.Value = x

scala> State.x
res2: State.Value = x

On 13 feb, 03:17, G J wrote:
> Can someone explain why IDLE is always printed as 'x'?
>
> object State extends Enumeration {
>     val IDLE, STARTED = Value
>     var x = IDLE
>
> }
>
> scala> State.x
> res16: State.Value = x                           // okay...
>
> scala> State.x = State.STARTED
> State.x: State.Value = STARTED
>
> scala> State.x
> res17: State.Value = STARTED             // expected.
>
> scala> State.x = State.IDLE
> State.x: State.Value = x                           // huh?
>
> scala> State.x
> res18: State.Value = x                            // what?
>
> Thanks.

Stefan Zeiger
Joined: 2008-12-21,
User offline. Last seen 27 weeks 3 days ago.
Re: Re: Scala Enumeration

On 2012-02-14 12:56, Jason Zaugg wrote:
> On Tue, Feb 14, 2012 at 12:46 PM, G J wrote:
>> Absolutely amazing! So much for Java portability.
>>
>> As clear as day light, it fails under OpenJDK [or in my version].
>> Anyone have a deeper understanding of the differences? Which one is
>> right....?
> "The elements in the array returned are not sorted and are not in any
> particular order"

I've opened https://issues.scala-lang.org/browse/SI-5462. Scala
reflection might give us the tools to improve this situation. OTOH,
macros could allow a much better implementation altogether.

-sz

Jan Vanek
Joined: 2011-08-23,
User offline. Last seen 42 years 45 weeks ago.
Re: Re: Scala Enumeration

On Tue, Feb 14, 2012 at 12:57 PM, Simon Ochsenreither <simon.ochsenreither@googlemail.com> wrote:
I would propose a compiler plugin to figure out if Enumerations is broken. For simplicity, it could be implemented by ignoring the input arguments and always returning true.

:-)
class StateClass extends Enumeration {   val IDLE = Value } val State = new StateClass def main(args: Array[String]) {    val bais = new ByteArrayOutputStream    val ois = new ObjectOutputStream(bais)    ois.writeObject(State.IDLE)    ois.flush    val baos = new ByteArrayInputStream(bais.toByteArray())    val oos = new ObjectInputStream(baos)    val state = oos.readObject().asInstanceOf[State.Value]    println(state) }
Serializable, huh?
Exception in thread "main" java.io.IOException: unexpected exception type at java.io.ObjectStreamClass.throwMiscException(Unknown Source) at java.io.ObjectStreamClass.invokeReadResolve(Unknown Source) at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) at java.io.ObjectInputStream.readObject0(Unknown Source) at java.io.ObjectInputStream.defaultReadFields(Unknown Source) at java.io.ObjectInputStream.readSerialData(Unknown Source) at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) at java.io.ObjectInputStream.readObject0(Unknown Source) at java.io.ObjectInputStream.readObject(Unknown Source) at scalaf.T$.main(T.scala:21) at scalaf.T.main(T.scala)Caused by: java.lang.NoSuchFieldException: MODULE$ at java.lang.Class.getField(Unknown Source) at scalaf.Enumeration.readResolve(Enumeration.scala:64) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) ... 10 more
Jan Vanek
Joined: 2011-08-23,
User offline. Last seen 42 years 45 weeks ago.
Re: Re: Scala Enumeration
It is related to: https://issues.scala-lang.org/browse/SI-2214 
Should have looked before... I think the enum should provide writeReplace method which would - in case the enum itself really is an object (determinable at runtime) - not serialize all its members, but only the class name. During deserialization it should read-resolve to the companion object. In the case the enum instance is not an object instance it would probably be best to serialize and deserialize it fully (into new instance, as usual objects).

On Tue, Feb 14, 2012 at 2:31 PM, Jan Vanek <j3vanek@googlemail.com> wrote:

On Tue, Feb 14, 2012 at 12:57 PM, Simon Ochsenreither <simon.ochsenreither@googlemail.com> wrote:
I would propose a compiler plugin to figure out if Enumerations is broken. For simplicity, it could be implemented by ignoring the input arguments and always returning true.

:-)
class StateClass extends Enumeration {   val IDLE = Value } val State = new StateClass def main(args: Array[String]) {    val bais = new ByteArrayOutputStream    val ois = new ObjectOutputStream(bais)    ois.writeObject(State.IDLE)    ois.flush    val baos = new ByteArrayInputStream(bais.toByteArray())    val oos = new ObjectInputStream(baos)    val state = oos.readObject().asInstanceOf[State.Value]    println(state) }
Serializable, huh?
Exception in thread "main" java.io.IOException: unexpected exception type at java.io.ObjectStreamClass.throwMiscException(Unknown Source) at java.io.ObjectStreamClass.invokeReadResolve(Unknown Source) at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) at java.io.ObjectInputStream.readObject0(Unknown Source) at java.io.ObjectInputStream.defaultReadFields(Unknown Source) at java.io.ObjectInputStream.readSerialData(Unknown Source) at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) at java.io.ObjectInputStream.readObject0(Unknown Source) at java.io.ObjectInputStream.readObject(Unknown Source) at scalaf.T$.main(T.scala:21) at scalaf.T.main(T.scala)Caused by: java.lang.NoSuchFieldException: MODULE$ at java.lang.Class.getField(Unknown Source) at scalaf.Enumeration.readResolve(Enumeration.scala:64) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) ... 10 more

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland