a decent enum is almost within reach

901 views
Skip to first unread message

Paul Phillips

unread,
Jun 4, 2012, 4:10:47 PM6/4/12
to Adriaan Moors, scala-l...@googlegroups.com
// Only ONE CLASSFILE no matter how many Bippies!
// Contrast with "object B1 extends Bippy", where we
// end up with two classes (B1 and B1$) per node.
object enum {
  // Oh, we can't make Bippy abstract else every instance has to be a subclass
  // A private constructor will have to suffice to "seal" it.
  sealed class Bippy private[enum] ()

  final val B1 = new Bippy   // infers B1.type
  final val B2 = new Bippy   // infers B2.type
  final val B3 = new Bippy   // infers B3.type

  // Now what we need is for scala to notice that Bippy is sealed
  // with a constructor which can only be invoked from this file, and
  // thus deduce that its *instances* are sealed - and we do not
  // need to cover "Bippy", only B1.type, B2.type, B3.type.

  def f(x: Bippy) = x match {
    case B1 => 1  // B1.type is covered
    case B2 => 2  // B2.type is covered
  }

  // hypothetically speaking
  warning: match may not be exhaustive.
  It would fail on the following input: B3
    def f(x: Bippy) = x match {
                      ^ }
}

Raoul Duke

unread,
Jun 4, 2012, 4:11:51 PM6/4/12
to scala-l...@googlegroups.com
> a decent enum is almost within reach

holy cow, like we are living in the future! this is exciting.

Alex Kravets

unread,
Jun 4, 2012, 5:47:41 PM6/4/12
to scala-l...@googlegroups.com
Hi Paul,

Although somewhat "pedestrian" if/when this type of enum really works, it will have a big impact.
 
I'll immediately convert our entire code base to using them instead of all the awkward cases of current usage like the code below (10+ cases in our code base)

<com/foo/package.scala>

type Count = Count.Value


<com/foo/Count.scala>

/**
*   Represents cardinality constants used in the schema definitions
*/
object Count extends Enumeration
{
  /** Zero or more (dot star) */
  val any   = Value

  /** Exactly one  (dot) */
  val one   = Value

  /** One or more  (dot plus)*/
  val some  = Value

  /** Zero or one  (dot question mark) */
  val opt   = Value
}


On Mon, Jun 4, 2012 at 1:11 PM, Raoul Duke <rao...@gmail.com> wrote:
> a decent enum is almost within reach

holy cow, like we are living in the future! this is exciting.



--
Alex Kravets       def redPill = 'Scala
[[ brutal honesty is the best policy ]]

Chris Marshall

unread,
Jun 5, 2012, 6:05:34 AM6/5/12
to scala-l...@googlegroups.com, Adriaan Moors, scala-l...@googlegroups.com
2 questions:

How does it print?
Can you get to the name (B1, B2 etc) from the instance easily and vice versa?

These are pretty much a must-have for them to be practicably useful. I'm thinking in terms of seeing them in log files, recovering values from a database etc...

Chris

Erik Post

unread,
Jun 5, 2012, 7:40:28 AM6/5/12
to scala-l...@googlegroups.com, Adriaan Moors
A withName returning Option[Value] instead of Value would be nice as well. 

Cheers,
Erik

√iktor Ҡlang

unread,
Jun 5, 2012, 8:51:02 AM6/5/12
to scala-l...@googlegroups.com, Adriaan Moors
On Tue, Jun 5, 2012 at 1:40 PM, Erik Post <eriks...@gmail.com> wrote:
A withName returning Option[Value] instead of Value would be nice as well. 

I'd prefer to avoid creating yet another naming convention and simply name it "get".

Cheers,
√ 



--
Viktor Klang

Akka Tech Lead
Typesafe - The software stack for applications that scale

Twitter: @viktorklang

Erik Post

unread,
Jun 5, 2012, 9:05:33 AM6/5/12
to scala-l...@googlegroups.com, Adriaan Moors
Agreed, withName is just the current name. I remember having read somewhere that there used to be a method that did return an Option[Value] btw. I can't imagine why that would have been replaced by this one.

Cheers,
Erik

On Tuesday, 5 June 2012 14:51:02 UTC+2, √iktor Klang wrote:

Klaus Havelund

unread,
Jun 5, 2012, 9:34:40 AM6/5/12
to scala-l...@googlegroups.com, Adriaan Moors
Do I understand correctly that you suggest to write an enumerated type
as follows:

object enum {
sealed class Bippy private[enum] ()

final val B1 = new Bippy
final val B2 = new Bippy
final val B3 = new Bippy
}

If have to admit that I find this notation slightly verbose. An
enumerated type should
preferably not be much more verbose than this (plus some keyword)
following the tradition
in many programming languages from the past:

enum = B1 | B2 | B3

or

enum = {B1,B2,B3}

or whatever.

It brings me also to the way we write for example a tree:

abstract class Tree
case object Empty extends Tree
case class Node(left: Tree, value: Int, right: Tree) extends Tree

This is also somewhat verbose considering the standard way of writing this in
other functional programming languages (and specification languages):

datatype tree = Empty | Node of {left: tree, data:int, right: tree}

or for the enumerated type:

datatype enum = B1 | B2

I am aware that the situation is more complex in an OO(+FP) language
since we might want to
add methods to the alternatives. I am not claiming that the solution
is obvious ... nor exists along the
lines I suggest.

Klaus Havelund

Rex Kerr

unread,
Jun 5, 2012, 10:27:19 AM6/5/12
to scala-l...@googlegroups.com, Adriaan Moors
Wouldn't standard Scala syntax work, i.e.

  final val B1, B2, B3 = new Bippy

?

  --Rex

Paul Phillips

unread,
Jun 5, 2012, 10:32:29 AM6/5/12
to scala-l...@googlegroups.com, Adriaan Moors


On Tue, Jun 5, 2012 at 6:34 AM, Klaus Havelund <have...@gmail.com> wrote:
Do I understand correctly that you suggest to write an enumerated type
as follows:
 
No, I was drawing attention to a possibility which only recently approached viability.  I wasn't proposing any finished products.

On Tue, Jun 5, 2012 at 7:27 AM, Rex Kerr <ich...@gmail.com> wrote:
Wouldn't standard Scala syntax work, i.e.

  final val B1, B2, B3 = new Bippy

It would, but without compiler support it would like the current enumeration have to rely on reflection to associate names with enum elements.  That's another ball of worms.  The reason I brought it up is the possibility of losing all those low-value classfiles.

Klaus Havelund

unread,
Jun 5, 2012, 10:34:02 AM6/5/12
to scala-l...@googlegroups.com, Adriaan Moors
All I can say is that even in Pascal, which is over 40 years old it looks nicer:

type enum = (B1, B2);

See various solutions to enumerated types here:

http://en.wikipedia.org/wiki/Enumerated_type

Scala is about to come out as the worst of these solutions.

Klaus


On Tue, Jun 5, 2012 at 7:27 AM, Rex Kerr <ich...@gmail.com> wrote:

√iktor Ҡlang

unread,
Jun 5, 2012, 10:35:30 AM6/5/12
to scala-l...@googlegroups.com, Adriaan Moors
On Tue, Jun 5, 2012 at 4:34 PM, Klaus Havelund <have...@gmail.com> wrote:
All I can say is that even in Pascal, which is over 40 years old it looks nicer:

 type enum = (B1, B2);

Isn't that a language level construct?
Or is this the apples vs pears challenge 2012?
 

See various solutions to enumerated types here:

 http://en.wikipedia.org/wiki/Enumerated_type

Scala is about to come out as the worst of these solutions.

Klaus


On Tue, Jun 5, 2012 at 7:27 AM, Rex Kerr <ich...@gmail.com> wrote:
> Wouldn't standard Scala syntax work, i.e.
>
>   final val B1, B2, B3 = new Bippy
>
> ?
>
>   --Rex
>
>
> On Tue, Jun 5, 2012 at 9:34 AM, Klaus Havelund <have...@gmail.com> wrote:
>>
>> Do I understand correctly that you suggest to write an enumerated type
>> as follows:
>>
>>  object enum {
>>    sealed class Bippy private[enum] ()
>>
>>    final val B1 = new Bippy
>>    final val B2 = new Bippy
>>    final val B3 = new Bippy
>>  }
>>
>> If have to admit that I find this notation slightly verbose.
>
>

Paul Phillips

unread,
Jun 5, 2012, 10:36:04 AM6/5/12
to scala-l...@googlegroups.com, Adriaan Moors


On Tue, Jun 5, 2012 at 7:34 AM, Klaus Havelund <have...@gmail.com> wrote:
Scala is about to come out as the worst of these solutions.

About to?

Alex Repain

unread,
Jun 5, 2012, 10:37:58 AM6/5/12
to scala-l...@googlegroups.com, Adriaan Moors
For inspiration :

http://rosettacode.org/wiki/Enumerations

2012/6/5 Paul Phillips <pa...@improving.org>

Paul Phillips

unread,
Jun 5, 2012, 11:15:11 AM6/5/12
to scala-l...@googlegroups.com, Adriaan Moors
In case anyone enjoys a little abuse of the machinery.  Please don't tell yourself this is the "next generation enum" or anything other than me amusing myself, although I believe this is more robust than what the current scala.Enumeration does to figure out the names.  The values have to be lazy vals so their identities can be inferred from the stack - if they're eager vals they originate in the constructor.  Then I kick off all the lazy vals via reflection to finish the enum.  It's sick, I know.  But look, it's almost concise.

object Test extends Enum {
  final lazy val B1, B2, B3, B4 = enum()
  
  def main(args: Array[String]): Unit = {
    println(names.mkString("names: ", ", ", ""))
    println(values.mkString("values: ", ", ", ""))
  }
  // names: B1, B2, B3, B4
  // values: B1, B2, B3, B4
}

class Enum {
  class Value private[Enum] (val name: String) { override def toString = name }
  private val buf = collection.mutable.ListBuffer[(String, Value)]()
  def names  = map.keys.toList
  def values = map.values.toList
  def apply(name: String) = map(name)
  def get(name: String)   = map get name

  def enum() = {
    val name   = Thread.currentThread.getStackTrace.iterator flatMap (f => computesLazyVal(f.getMethodName)) next
    val elem   = new Value(name)
    buf += ((name, elem))
    elem
  }
  lazy val map = {
    val ms       = getClass.getDeclaredMethods
    val computed = Set(ms map (_.getName) flatMap computesLazyVal: _*)
    ms filter (m => computed(m.getName) && m.getParameterTypes.isEmpty) foreach (_ invoke this)

    try collection.immutable.SortedMap(buf.toList: _*)
    finally buf.clear()
  }
  private def computesLazyVal(name: String) =
    if (name endsWith "$lzycompute") Some(name stripSuffix "$lzycompute") else None
}


John Nilsson

unread,
Jun 5, 2012, 11:29:56 AM6/5/12
to scala-l...@googlegroups.com

Requiring lazy could be a little rough though. I imagine it could be the source of much confusion and feel a little ad-hoc.

Would it be possible to get around it with the delayed initialization used to implement App?

BR
John

Tony Morris

unread,
Jun 5, 2012, 5:57:26 PM6/5/12
to scala-l...@googlegroups.com, Adriaan Moors

You could also integrate a type-level natural number (shapeless) and provide a bijection lens to the enumeration. Or just do what java does and use Intyuk.

Nils Kilden-Pedersen

unread,
Jun 6, 2012, 6:27:03 AM6/6/12
to scala-l...@googlegroups.com
Is there any way macros can be useful in a better enum?

Stefan Zeiger

unread,
Jun 6, 2012, 7:00:02 AM6/6/12
to scala-l...@googlegroups.com
On 2012-06-06 12:27, Nils Kilden-Pedersen wrote:
> Is there any way macros can be useful in a better enum?

Once we get type macros it should be possible to auto-generate enums, so
you'd only have to write something like

object MyEnum extends Enum('B1, 'B2, 'B3)

Simon Ochsenreither

unread,
Jun 6, 2012, 1:40:33 PM6/6/12
to scala-l...@googlegroups.com, Adriaan Moors
Cool, great work!

I have thought about the various approaches to enums a bit and without diminishing any of the work you or others have done, I've come to the following points:

  • The current approach — scala.Enumeration — has basically zero adoption, partially due to missing basic functionality like exhaustiveness checks and due to its bug-ridden past.
  • Almost everyone either takes the route of a sealed class with a bunch of objects instead (which comes with a lot of class file overhead) or just uses Java enums, which work perfectly fine.

I think it makes sense to step a bit back and question whether we actually need some Scala-proprietary enum functionality:
Java enums considered to be one of the good parts of Java. enums are not a hot research topic, so why does Scala play NIH here, when it doesn't actually improve substantially on Java enums?

Imho it makes sense to split the issue into two parts:

  1. How should “Scala” enums end up from the bytecode perspective?
  2. How should the syntax look like.

On question number 1: I think it makes a lot of sense to emit bytecode equivalent to Java enums. Currently, they are substantially different (and incompatible) and it is just a PITA, without any good reason.

On question number 2: As much as I hate special cases, maybe this is one of the cases where it needs to happen. What about some “enum” keyword which does comparable magic as “case”. For instance, “enum” could generate the methods which are also generated by javac and probably add some apply/unapply methods for convenience/pattern matching.


In the end, I think Scala should use Java enums, either by emitting the corresponding bytecode or by telling that scala has no enums and people should use javac to define their enums. The current situation is that we have two different approaches, both incompatible with each other and with their own benefits and drawbacks, and as soon as a developer wants to enable use from Java, he has to rewrite them as Java enums.

Personally, I tend to use 100% Java enums and It would be great being able to define them without having to go back to javac.


TL;DR:

The current approaches are not great, would it be possible to map Scala enums to Java enums in the compiler and be done with it, once and for all?


Thanks and bye,


Simon

Alex Repain

unread,
Jun 6, 2012, 2:09:47 PM6/6/12
to scala-l...@googlegroups.com
I personnally hate the idea  of Scala being so dependable on Java. It makes me feel like I'm using half a language, and when promoting Scala, if someone asks me a question where I can only answer "it uses Java for that", I feel almost ashamed. -1 to simply using Java enums, despite the fact that they work quite well...

2012/6/6 Simon Ochsenreither <simon.och...@googlemail.com>

Raoul Duke

unread,
Jun 6, 2012, 2:11:28 PM6/6/12
to scala-l...@googlegroups.com
> I personnally hate the idea  of Scala being so dependable on Java.

on the one hand, i can totally relate.

on the other hand: uh, wow. like, why aren't you just using haskell or
something? (the deal with the devil was made from the get-go, you
know.)

sincerely.

Alex Repain

unread,
Jun 6, 2012, 2:18:47 PM6/6/12
to scala-l...@googlegroups.com


2012/6/6 Raoul Duke <rao...@gmail.com>

That's not my point. I don't seek purity or what, I just feel sometimes that Scala looks like a crippled language that is only standing because Java is supporting it. Not to me, but to people you tell about it. It's hard to explain how Scala is better than Java in many points, and at the same time, explain that some of the core of Scala is just actually Java. So, I'm against extending that part of the core that relies on Java. Talk about deal with the devil ... Well yeah. I'm looking forward to a JVM-less version of Scala. If it never happens, I'll continue with that Scala anyway, it's just great enough. :)


sincerely.

Kevin Wright

unread,
Jun 6, 2012, 2:25:48 PM6/6/12
to scala-l...@googlegroups.com
I consider myself to be a Java programmer, it's just that I'm referring to the platform and not the language :)

In that vein... Much as I hate the idea of special cases, having an effective enum type would certainly have helped with the various Java->Scala migrations I've been involved in, seeing the mess that IntelliJ conversion makes of it almost makes me want to cry!

Java's enums may be ugly, but it's uglier still being driven to keep them in Java and then spending some time with a mixed codebase.

Simon Ochsenreither

unread,
Jun 6, 2012, 2:33:16 PM6/6/12
to scala-l...@googlegroups.com
I personnally hate the idea  of Scala being so dependable on Java. It makes me feel like I'm using half a language, and when promoting Scala, if someone asks me a question where I can only answer "it uses Java for that", I feel almost ashamed.

Sorry, I don't follow ... do you disagree with using Java-the-language for defining enums or that Scala should emit bytecode which looks like “real” Java enums?
 
-1 to simply using Java enums, despite the fact that they work quite well...

Well, Java enums are the only option if you want to be efficient, interoperable and bug-free. I would love if there was a way in Scala to write them. Until that happens, I just use javac.

martin odersky

unread,
Jun 6, 2012, 2:36:56 PM6/6/12
to scala-l...@googlegroups.com
Do Java enums have exhaustiveness checks? I think not. So are we collectively barking up the wrong tree here?

Taking a step back, can we identify what's wrong with Enumeration today (never mind it's bug-ridden past). I can identify two problem areas:

(1) Automatic name detection is fickle because it relies on coding patterns that can be circumvented.

(2) All enums erase to the same type so you cannot overload methods that take different enum types.

Is there anything else?

Cheers

 - Martin

Klaus Havelund

unread,
Jun 6, 2012, 2:41:28 PM6/6/12
to scala-l...@googlegroups.com
> Is there anything else?

My original comment focused on just the notation, which is verbose.

Klaus

Alex Repain

unread,
Jun 6, 2012, 2:54:59 PM6/6/12
to scala-l...@googlegroups.com


2012/6/6 Simon Ochsenreither <simon.och...@googlemail.com>

I personnally hate the idea  of Scala being so dependable on Java. It makes me feel like I'm using half a language, and when promoting Scala, if someone asks me a question where I can only answer "it uses Java for that", I feel almost ashamed.

Sorry, I don't follow ... do you disagree with using Java-the-language for defining enums or that Scala should emit bytecode which looks like “real” Java enums?

Java the language. The idea that was suggested was to make use of Java enums through compilation of Scala enums, which means giving a nice syntax but relying on Java behind the scene. Or maybe I didn't understand the proposal correctly ? I sure have no problem with producing bytecode (through scalac only) that "fits Javac's bytecode". the JVM was made altogether with Java, it's only logical that Scala bytecode should be close to Java bytecode.

 
-1 to simply using Java enums, despite the fact that they work quite well...

Well, Java enums are the only option if you want to be efficient, interoperable and bug-free. I would love if there was a way in Scala to write them. Until that happens, I just use javac.


I don't really care for interoperability, but I understand how much of a concern it can be, especially where Scala is used by "Java refugees" :).

Simon Ochsenreither

unread,
Jun 6, 2012, 4:20:52 PM6/6/12
to scala-l...@googlegroups.com
Hi Martin,



Do Java enums have exhaustiveness checks? I think not. So are we collectively barking up the wrong tree here?

Just checked. You are absolutely right, it doesn't. I was totally sure javac would bark at me ... but it even forces to add a useless return statement to code like this:

public enum Foo {
  A, B
}

public static boolean isA(Foo foo){
    switch(foo){
        case A: return true;
        case A: return false;         
    }
    return false; // <--- :-(
}
 
I think checking exhaustiveness is still a sensible requirement for enums regardless of Java's support for it.


Taking a step back, can we identify what's wrong with Enumeration today (never mind it's bug-ridden past). I can identify two problem areas:

(1) Automatic name detection is fickle because it relies on coding patterns that can be circumvented.

(2) All enums erase to the same type so you cannot overload methods that take different enum types.

Is there anything else?

I would add
  • Syntax is non-obvious, especially when you want to add arguments to each enum item.
  • Non-interoperable with Java for no good reason.
  • And bugs like SI-4570, SI-4805, SI-5534, SI-3314, SI-3815, SI-5462, SI-5147, ...

Thanks and bye,


Simon

Daniel Sobral

unread,
Jun 6, 2012, 5:22:43 PM6/6/12
to scala-l...@googlegroups.com
It ought to bark if you *omit* a case. Unreachability is a completely
different thing.
--
Daniel C. Sobral

I travel to the future all the time.

Daniel Sobral

unread,
Jun 6, 2012, 5:33:35 PM6/6/12
to scala-l...@googlegroups.com
Besides, you checked twice for A, instead of checking for A and B.
Nevertheless, I can confirm it does not test for exhaustivity. In
fact, switching on Enum is counter-indicated on Effective Java for
just such a reason. Interestingly, it also mentions the
return-after-switch. Points to JLS, 14.21.

On Wed, Jun 6, 2012 at 5:20 PM, Simon Ochsenreither
<simon.och...@googlemail.com> wrote:

Erik Post

unread,
Jun 6, 2012, 8:59:42 PM6/6/12
to scala-l...@googlegroups.com
> Is there anything else?

I was rather surprised during my recent foray into enum land to find that withName() returns a Value instead of an Option[Value]. In addition, as someone pointed out above, the naming of withName itself seems a bit unusual in that it uses 'with'.

Cheers,
Erik

Nils Kilden-Pedersen

unread,
Jun 7, 2012, 3:42:39 AM6/7/12
to scala-l...@googlegroups.com
On Wed, Jun 6, 2012 at 9:20 PM, Simon Ochsenreither <simon.och...@googlemail.com> wrote:

Do Java enums have exhaustiveness checks? I think not. So are we collectively barking up the wrong tree here?

Just checked. You are absolutely right, it doesn't. I was totally sure javac would bark at me

The Eclipse compiler does, which once again proves it superior to javac.

Nils Kilden-Pedersen

unread,
Jun 7, 2012, 3:48:38 AM6/7/12
to scala-l...@googlegroups.com
For reference:
Preferences->Java->Compiler->Errors/Warnings->Potential programming problems->Enum type constant not covered on 'switch'

Nils Kilden-Pedersen

unread,
Jun 7, 2012, 3:52:09 AM6/7/12
to scala-l...@googlegroups.com

(3) Exhaustiveness checking

I don't see why javac should be the mediocre goal here.

Ismael Juma

unread,
Jun 7, 2012, 4:11:05 AM6/7/12
to scala-l...@googlegroups.com
On Wed, Jun 6, 2012 at 7:36 PM, martin odersky <martin....@epfl.ch> wrote:
Is there anything else?

Another handy benefit of using Java enums is that one can use the highly optimised EnumMap.

Best,
Ismael

Simon Ochsenreither

unread,
Jun 7, 2012, 5:08:50 AM6/7/12
to scala-l...@googlegroups.com

> << Total example fail >>

Yes, you're right. No idea how I got the example so messed up. I meant A and B of course.

Peter C. Chapin

unread,
Jun 7, 2012, 8:45:26 AM6/7/12
to scala-l...@googlegroups.com, Adriaan Moors
I actually use Scala enums quite a bit. My programming is such that enumeration types are often useful to me and I consider the limitations of Scala enums minor. I don't care about Java interoperability and I would recommend against "just use Java" as a solution. For one thing that won't help Scala.NET or Scala targeting LLVM.

My main concern about Scala enums is that their definition is counter intuitive to me. Despite using them regularly I find that I constantly have to look up the syntax. I'm used to defining enums in Ada like this

type Color_Type is (Red, Green, Blue);

For me, that is very simple and straightforward.

Peter

Erik Post

unread,
Jun 7, 2012, 8:51:43 AM6/7/12
to scala-l...@googlegroups.com, Adriaan Moors
For what it's worth, I also find the syntax hard to remember.

Cheers,
Erik

√iktor Ҡlang

unread,
Jun 7, 2012, 9:22:11 AM6/7/12
to scala-l...@googlegroups.com, Adriaan Moors


On Mon, Jun 4, 2012 at 10:10 PM, Paul Phillips <pa...@improving.org> wrote:
// Only ONE CLASSFILE no matter how many Bippies!
// Contrast with "object B1 extends Bippy", where we
// end up with two classes (B1 and B1$) per node.
object enum {
  // Oh, we can't make Bippy abstract else every instance has to be a subclass
  // A private constructor will have to suffice to "seal" it.
  sealed class Bippy private[enum] ()

  final val B1 = new Bippy   // infers B1.type
  final val B2 = new Bippy   // infers B2.type
  final val B3 = new Bippy   // infers B3.type

Then this should also be fine:

final val B1, B2, B3 = new Bippy

Cheers,
 

  // Now what we need is for scala to notice that Bippy is sealed
  // with a constructor which can only be invoked from this file, and
  // thus deduce that its *instances* are sealed - and we do not
  // need to cover "Bippy", only B1.type, B2.type, B3.type.

  def f(x: Bippy) = x match {
    case B1 => 1  // B1.type is covered
    case B2 => 2  // B2.type is covered
  }

  // hypothetically speaking
  warning: match may not be exhaustive.
  It would fail on the following input: B3
    def f(x: Bippy) = x match {
                      ^ }
}




--
Viktor Klang

Akka Tech Lead
Typesafe - The software stack for applications that scale

Twitter: @viktorklang

Ant Kutschera

unread,
Aug 17, 2012, 5:13:39 PM8/17/12
to scala-l...@googlegroups.com
On Wednesday, 6 June 2012 20:36:56 UTC+2, martin wrote:
Do Java enums have exhaustiveness checks? I think not. So are we collectively barking up the wrong tree here?
.
Is there anything else?


Hi,

Does Scala have an equivalent to EnumSet?

Also, in Java, the name is independent of toString.  So I might have a Java enum where toString gives out some techy info which might be good during debugging/logging, but I can still use it's name if I want to persist the enum.  Eg:

public enum Colour {

Red(255, 0, 0),
Orange(255, 102, 0),
Yellow(255, 255, 0),
Green(0, 128, 0),
Blue(0, 0, 255),
Indigo(0, 0, 81),
Violet(128, 0, 128);
private final int r;
private final int g;
private final int b;
Colour(int r, int g, int b){
this.r = r;
this.g = g;
this.b = b;
}

public int getB() {
return b;
}
public int getG() {
return g;
}
public int getR() {
return r;
}
public static Colour valueOf(final int r, final int g, final int b){
for(Colour c : Colour.values()){
if(c.r == r && c.g == g && c.b == b){
return c;
}
}
throw new IllegalArgumentException("no known colour with components (" + r + "," + g + "," + b + ")");
}
@Override
public String toString() {
return name() + "(" + r + "," + g + "," + b + ")";
}
}


In Scala, the name, and toString seem to be related, although I could just be implementing a complex Enum wrong...  However inside Enumeration, the withName method depends on Value#toString.

Here is a Scala example (I assume I have done the right thing by extending Val and creating a Value factory method - can anyone give me feedback?):


    object Colour1 extends scala.Enumeration {

        /** since we want our enum to be more complex, we must extend Val */
    protected class MyVal(val r: Int, val g: Int, val b: Int) extends Val() {
       override def toString = super.toString + "("+r+","+g+","+b+")"
     }
        
    /** create a factory method, which uses our extension of Val */
        def Value(r: Int, g: Int, b: Int) = new MyVal(r, g, b)

        /** a standard finder method, for locating the enum instance based on our complex data */
        def valueOf(r: Int, g: Int, b: Int) = {
            values.find(v => {
            val mv = v.asInstanceOf[MyVal]
    r == mv.r && g == mv.g && b == mv.b
            }).get
        }

        /* define the enums now: */

        val Red = Value(255,0,0)
val Orange = Value(255,102,0)
val Yellow = Value(255,255,0)
val Green = Value(128,0,0)
val Blue = Value(0,0,255)
val Indigo = Value(0,0,81)
val Violet = Value(128,0,128)
    }


The problem with that is that:

Colour1.withName("Orange") doesn't work, because Enumeration compares with toString, which I have overriden.  I would need to do Colour1.withName("Orange(255,102,0)").

What is also not to nice with the above solution is that I have to cast, if I want to create my own finder methods (valueOf), because the values method returns Value instances, rather than the subclass.  Eg:

        def valueOf(s: String): MyVal = values.find(_.asInstanceOf[MyVal].name == s).get.asInstanceOf[MyVal]        

I have to cast twice there.  Is there a way around this?

These two "problems" (name/toString and casting) are not problems with Java.

For the name/toString issue, I have a patch for scala.Enumeration, which I think doesn't break the interface, so it's backward compatible, but I haven't checked it too much. Here it is:

------------------------------------------------------
--- C:/temp/m/scala/Enumeration.scala Fri Aug 17 23:02:29 2012
+++ C:/temp/m/scala/EnumerationPatched.scala Fri Aug 17 23:02:29 2012
@@ -50,7 +50,7 @@
  *                 identifies values at run-time.
  *  @author  Matthias Zenger
  */
-@SerialVersionUID(8476000850333817230L)
+@SerialVersionUID(211L)
 abstract class Enumeration (initial: Int) extends Serializable {
   thisenum =>
 
@@ -129,7 +129,7 @@
    * @throws   java.util.NoSuchElementException if no `Value` with a matching
    *           name is in this `Enumeration`
    */
-  final def withName(s: String): Value = values.find(_.toString == s).get
+  final def withName(s: String): Value = values.find(_.name == s).get
 
   /** Creates a fresh value, part of this enumeration. */
   protected final def Value: Value = Value(nextId)
@@ -187,10 +187,14 @@
   private def nameOf(i: Int): String = synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
 
   /** The type of the enumerated values. */
-  @SerialVersionUID(7091335633555234129L)
+  @SerialVersionUID(211L)
   abstract class Value extends Ordered[Value] with Serializable {
     /** the id and bit location of this enumeration value */
     def id: Int
+
+    /** the name of this enumeration value */
+    def name: String
+    
     /** a marker so we can tell whose values belong to whom come reflective-naming time */
     private[Enumeration] val outerEnum = thisenum
 
@@ -209,8 +213,8 @@
    *  can be overridden to change the enumeration's naming and integer
    *  identification behaviour.
    */
-  @SerialVersionUID(0 - 3501153230598116017L)
-  protected class Val(i: Int, name: String) extends Value with Serializable {
+  @SerialVersionUID(211L)
+  protected class Val(i: Int, myName: String) extends Value with Serializable {
     def this(i: Int)       = this(i, nextNameOrNull)
     def this(name: String) = this(nextId, name)
     def this()             = this(nextId)
@@ -222,10 +226,11 @@
     if (nextId > topId) topId = nextId
     if (i < bottomId) bottomId = i
     def id = i
-    override def toString() =
-      if (name != null) name
+    def name = 
+      if (myName != null) myName
       else try thisenum.nameOf(i)
       catch { case _: NoSuchElementException => "<Invalid enum: no field for #" + i + ">" }
+    override def toString() = name
 
     protected def readResolve(): AnyRef = {
       val enum = thisenum.readResolve().asInstanceOf[Enumeration]
------------------------------------------------------


Cheers,
Ant

 
Reply all
Reply to author
Forward
0 new messages