Enumeration must DIE...

7,810 views
Skip to first unread message

Som Snytt

unread,
Oct 19, 2012, 8:00:29 PM10/19/12
to scala-internals
...where DIE = Divergent Implicit Expansion.

While looking at the DIE issue with mapping Enumeration values
https://issues.scala-lang.org/browse/SI-5534

I noticed that one quick fix is to make Value no longer Ordered.

My question is whether the "id" or "ordinal" for Enumeration.Values should be internal detail.  By extension, we can remove Ordered.  I moved the Ordering[Value] to a related companion class.

As an example, Reporter.Severity is a Value used just as an int wrapper. I had to add Ordered back to Severity for INFO < ERROR tests.

I reread the DIE page of the spec, combed through the -Yinfer-debug, and more/less understand what's intended by the newCBF for SortedSet.  However, my understanding is only 66% so far on the implicit problem, so I don't want to suggest that this is the optimal fix.

Also of interest, ValueSet uses an underlying BitSet, so you lose a bit of range:
https://issues.scala-lang.org/browse/SI-6094
but probably ValueSet doesn't want to create sparse BitSets with huge ranges anyway and should switch to a different representation after a relatively small topId - bottomId.

If ids were only ordinals, with bottomId always zero, the conceptual model would be as simple as it really is.

Simon Ochsenreither

unread,
Oct 20, 2012, 6:03:11 PM10/20/12
to scala-i...@googlegroups.com
scala.Enumerations have caused nothing but trouble as far as I can think back ... I wonder when it is finally enough and Scala will just use the JVM's/Java's enums. Maybe macros will get us a lot closer to some sane, interoperable solution by synthesizing the appropriate methods, just like javac does.

Som Snytt

unread,
Oct 20, 2012, 10:51:13 PM10/20/12
to scala-i...@googlegroups.com
On Sat, Oct 20, 2012 at 3:03 PM, Simon Ochsenreither <simon.och...@gmail.com> wrote:
scala.Enumerations have caused nothing but trouble as far as I can think back ... I wonder when it is finally enough and Scala will just use the JVM's/Java's enums. Maybe macros will get us a lot closer to some sane, interoperable solution by synthesizing the appropriate methods, just like javac does.

I should add that while I understand this point of view, in the subject line I was only being flippant (which I hope has nothing to do with flipping off, but one can't be sure about French terms).  Or maybe the word is glib.  Let's say, flib, which is a flub that went over the top.

I actually like Enumeration as a showcase module.
http://www.artima.com/pins1ed/abstract-members.html#20.8

It's been hard to get exactly right, but only in a good way.  The last issue was, "Enum doesn't know how to compare two ints."  Enumeration really deserves its own section on Scala Puzzlers.  As the other thread on enums and case objects shows, there should be a whole other section on enum alternatives.

I was kind of surprised that paulp hasn't taken a big hammer to Enumeration, but I just checked the history and there's a "Fix for Enumeration" followed shortly thereafter by a 'Revert "Fix for Enumeration".'   Just because a task is difficult and thankless, doesn't mean it's not worth trying.

In the current issue, the set of values became a sorted set, and the code was made to imitate BitSet (which it happens to use under the hood).  BitSet works nicely as a SortedSet[Int], but ValueSet as SortedSet[Value] demonstrates this glitch.  (Because Value is Ordered, and Pair[Ordered, _] picks up the implicit that seems to DIE.)

For me, the motivation is to understand implicits, the Ordering apparatus, and how to extend collections.  I think that may rate a puzzler.


martin odersky

unread,
Oct 21, 2012, 4:10:18 AM10/21/12
to scala-i...@googlegroups.com


On Sun, Oct 21, 2012 at 12:03 AM, Simon Ochsenreither <simon.och...@gmail.com> wrote:
scala.Enumerations have caused nothing but trouble as far as I can think back ... I wonder when it is finally enough and Scala will just use the JVM's/Java's enums. Maybe macros will get us a lot closer to some sane, interoperable solution by synthesizing the appropriate methods, just like javac does.

You can use Java enums. But Scala will never have them. 

I have to repeat my mantra once more here: My intention is to make Scala a simpler language, with fewer features, not more. Most of the discussion on the Scala lists goes the other way, where everyone is rooting for just one more essential feature. That's only natural. But I have by now developed a high level of resistance to most of these proposals.

Cheers

 - Martin


Simon Ochsenreither

unread,
Oct 21, 2012, 11:15:58 AM10/21/12
to scala-i...@googlegroups.com
Hi Martin,

I think we are in perfect agreement on that!

I just assumed that Scala absolutely needed some native, Java-enum-like replacement. If that's not the case and using Java for this purpose is considered fine, forget about my considerations on how to implement Java-compatible enums in Scala without introducing new features.

Let's deprecate scala.Enumeration in 2.11 and guide people either towards Java's enums or Scala's ADT-like approach.

One feature less, less bugs, less confusion on what to use (see https://groups.google.com/d/topic/scala-user/2g-qzsfE0Us/discussion, https://groups.google.com/d/topic/scala-user/2ZiLW92ieq4/discussion), better interop and no need to duplicate APIs for Java/Scala enums. (Considering the usage on scala.Enumeration in the wild, it seems people already voted with their feet, too.)

Thanks and bye,

Simon

Paul Phillips

unread,
Oct 21, 2012, 11:16:03 AM10/21/12
to scala-i...@googlegroups.com


On Sun, Oct 21, 2012 at 1:10 AM, martin odersky <martin....@epfl.ch> wrote:
I have to repeat my mantra once more here: My intention is to make Scala a simpler language, with fewer features, not more. Most of the discussion on the Scala lists goes the other way, where everyone is rooting for just one more essential feature. That's only natural. But I have by now developed a high level of resistance to most of these proposals.

This seems like a questionable example of people rooting for one more feature; the primary thing being rooted for when it comes to scala.Enumeration is its removal. I thought leveraging java's existing and satisfactory solutions where possible was scala's thing.

Ismael Juma

unread,
Oct 21, 2012, 12:01:59 PM10/21/12
to scala-i...@googlegroups.com
On Sun, Oct 21, 2012 at 4:16 PM, Paul Phillips <pa...@improving.org> wrote:
This seems like a questionable example of people rooting for one more feature; the primary thing being rooted for when it comes to scala.Enumeration is its removal. I thought leveraging java's existing and satisfactory solutions where possible was scala's thing.

Particularly since 2.10 is meant to include exhaustiveness checks for Java enums too.

Best,
Ismael 

martin odersky

unread,
Oct 21, 2012, 3:05:45 PM10/21/12
to scala-i...@googlegroups.com
I think Enumeration works fine for what it's supposed to do: Provide enumerations without the overhead of one class per value. It beats the alternative of defining numeric constants, for sure.

Cheers

 - Martin



Paul Phillips

unread,
Oct 21, 2012, 3:09:41 PM10/21/12
to scala-i...@googlegroups.com


On Sun, Oct 21, 2012 at 12:05 PM, martin odersky <martin....@epfl.ch> wrote:
Provide enumerations without the overhead of one class per value.

Two classes per value, usually, not that case objects are the only imaginable alternative.  But "works fine" is one of those subjective things.  I like my scala features to work at least as well as the java feature they are reimplementing.  By that standard it does not rise to the level of fine.

martin odersky

unread,
Oct 21, 2012, 3:11:24 PM10/21/12
to scala-i...@googlegroups.com
Yes, but it also has a whole lot less language footprint (to be exact: zero). Enumerations in Java are quite enormous, similar in complexity to, say, traits in Scala.  Is the convenience really worth it?

Cheers

 - Martin



Simon Ochsenreither

unread,
Oct 21, 2012, 3:32:42 PM10/21/12
to scala-i...@googlegroups.com
Enumerations in Java are quite enormous, similar in complexity to, say, traits in Scala.  Is the convenience really worth it?

As far as I have understood it, people in this thread are arguing to get rid of scala's bug-ridden, non-interoperable implementation in favor of just using Java's enums, not about changing Scala-the-language to add anything to it.

The convenience of not having to deal with scala.Enumeration and the poor souls who fell into the trap using it has no impact on the language footprint, but imho a lot of positive impact on people learning Scala.

Rex Kerr

unread,
Oct 21, 2012, 4:11:15 PM10/21/12
to scala-i...@googlegroups.com
On Sun, Oct 21, 2012 at 3:05 PM, martin odersky <martin....@epfl.ch> wrote:

I think Enumeration works fine for what it's supposed to do: Provide enumerations without the overhead of one
class per value. It beats the alternative of defining numeric constants, for sure.

Well, occasionally I suppose it does.  It's integer-only (numeric constants are not), boxed (numeric constants are not), and allows (at compile-time) but breaks on repeated values (numeric constants allow repeats and do not break):

    object Wrong extends Enumeration { val a,b = Value(2) }

It can't check for complete pattern matches (unlike the case where classes are used), and admits various weird usages that fail at runtime:

    object Okay extends Enumeration { val c = Value }
    object Uhoh extends Enumeration { val d = Okay.Value }

And although it doesn't add to the _language_ complexity, it does add to the _library_ complexity.  It's amazing that it works at all, but even so it doesn't work very well.

In practice, between needing byte and short and floating point constants, and needing pattern matching, and needing bitmasks for which Enumeration generates the wrong progression, I hardly use it at all.

I would use it more if it was something like

class Incrementable[T](val zero: T, val inc: T => T) {}
abstract class Enumeration[T: Incrementable] { ... }

  --Rex

Erik Osheim

unread,
Oct 21, 2012, 4:18:25 PM10/21/12
to scala-i...@googlegroups.com
On Sun, Oct 21, 2012 at 04:11:15PM -0400, Rex Kerr wrote:
> In practice, between needing byte and short and floating point constants,
> and needing pattern matching, and needing bitmasks for which Enumeration
> generates the wrong progression, I hardly use it at all.

Yeah, that's been my experience as well. Ugly-but-verbose numeric
constants are reliable, represent the (unboxed) values and types I
need, and be be easily inlined if that's what I want.

-- Erik

martin odersky

unread,
Oct 21, 2012, 4:22:26 PM10/21/12
to scala-i...@googlegroups.com
On Sun, Oct 21, 2012 at 10:11 PM, Rex Kerr <ich...@gmail.com> wrote:
On Sun, Oct 21, 2012 at 3:05 PM, martin odersky <martin....@epfl.ch> wrote:

I think Enumeration works fine for what it's supposed to do: Provide enumerations without the overhead of one
class per value. It beats the alternative of defining numeric constants, for sure.

Well, occasionally I suppose it does.  It's integer-only (numeric constants are not), boxed (numeric constants are not), and allows (at compile-time) but breaks on repeated values (numeric constants allow repeats and do not break):

    object Wrong extends Enumeration { val a,b = Value(2) }

It can't check for complete pattern matches (unlike the case where classes are used), and admits various weird usages that fail at runtime:

    object Okay extends Enumeration { val c = Value }
    object Uhoh extends Enumeration { val d = Okay.Value }

Enumeration comes with a usage pattern. If you use it wrongly, it breaks. I do not see much that's wrong with that. If you use the wrong numeric constants (ie the same one twice) your program will break as well. And that is usually harder to guard against than just writing

  val a, b, c = Value

To each their own. People who do not like enumeration do not need to use it. Sometimes numeric constants are better. But if you do not want to watch out for duplicate values manually, 
and you do not need utmost performance, enumerations are nice.

Cheers

 - Martin


And although it doesn't add to the _language_ complexity, it does add to the _library_ complexity.  It's amazing that it works at all, but even so it doesn't work very well.

In practice, between needing byte and short and floating point constants, and needing pattern matching, and needing bitmasks for which Enumeration generates the wrong progression, I hardly use it at all.

I would use it more if it was something like

class Incrementable[T](val zero: T, val inc: T => T) {}
abstract class Enumeration[T: Incrementable] { ... }

Note that java enums only map to ints as well.

But to 

 


  --Rex




--
Martin Odersky
Prof., EPFL and Chairman, Typesafe
PSED, 1015 Lausanne, Switzerland
Tel. EPFL: +41 21 693 6863
Tel. Typesafe: +41 21 691 4967

Simon Ochsenreither

unread,
Oct 21, 2012, 5:38:51 PM10/21/12
to scala-i...@googlegroups.com
Hi,


Enumeration comes with a usage pattern. If you use it wrongly, it breaks. I do not see much that's wrong with that.
I honestly can't remember scala.Enumeration's "right" usage without looking it every time I considered using it. That alones leaves a very bad taste.
Java managed to completely prevent this problem of "wrong usage patterns". To this day, I haven't seen a definition of Java's enum which both compiled _and_ broke at runtime.
Why would we consider less than this acceptable for Scala?

If you use the wrong numeric constants (ie the same one twice) your program will break as well. And that is usually harder to guard against than just writing
The issue, as far as I have understood it, is that people actually choose to go back to some less expressive and less semantically exact code instead of using Scala's Enumeration.
The only "static final int"s I see in Java are pre-enums. It seems that Scala's Enumeration didn't even manage to solve this basic requirement in a way people would actually want to use it.

To each their own. People who do not like enumeration do not need to use it.
Sometimes numeric constants are better. But if you do not want to watch out for duplicate values manually, 
and you do not need utmost performance, enumerations are nice.
With type aliases and value types there are even more options for safe, declarative code, but I think that's besides the point.
scala.Enumerations doesn't seem to solve any actual issue and has all the drawbacks of not being a java.lang.Enum (like in annotations).
People who want to use enumerations should use Java enums, they don't deserve that we waste their time with scala.Enumeration. So can we get rid of scala.Enumeration, please?

Thanks and bye,

Simon


Rex Kerr

unread,
Oct 21, 2012, 5:44:20 PM10/21/12
to scala-i...@googlegroups.com

Can we try rewriting it first, taking advantage of the huge increase in experience with writing reliable Scala library code and experience with the difficulties of the existing version?

Or maybe wait until we have a proper units system--if we're going to get one--so that we can leverage that for type-safety?

  --Rex

Simon Ochsenreither

unread,
Oct 21, 2012, 6:04:29 PM10/21/12
to scala-i...@googlegroups.com

Can we try rewriting it first, taking advantage of the huge increase in experience with writing reliable Scala library code and experience with the difficulties of the existing version?
That's what I proposed in the first comment, but that was shot down. Also, I don't see how we could make scala.Enumeration a Java enum without tons of macro magic. In the end, it would be more like some Scala-like DSL where the macro would completely rewrite the tree of the "enum declaration". This couldn't be done with method-level macros, we would probably need macro types or macro annotations for that.

Rex Kerr

unread,
Oct 21, 2012, 6:26:06 PM10/21/12
to scala-i...@googlegroups.com
Well, you proposed a specific rewrite for it, which was basically to use macros to mimic Java enums, which was shot down.  Even without going that far, one could make some significant improvements--not to Java interop, but to robustness, flexibility, speed, etc. (not all at once--one would need to decide what to target).

  --Rex

Simon Ochsenreither

unread,
Oct 21, 2012, 6:56:10 PM10/21/12
to scala-i...@googlegroups.com
If the rewritten scala.Enumeration isn't compatible with Java enums, why even bother rewriting it? I prefer a useless implementation with known bugs to a useless implementation with unknown bugs.
There is a reason why practically no-one uses scala.Enumeration and "incompatible with the platform' idea of enums" and "buggy" rank pretty high on my list of suspects.

Nothing against a bit of NIH, but there is only one valid definition of "enum" and that's the one of the JVM. If the JVM tells me "no, that's not an enum, I won't allow you to use this in an annotation" I don't care about Scala's reason for failing to work as expected.

Thanks and bye,

Simon

Rex Kerr

unread,
Oct 21, 2012, 7:34:17 PM10/21/12
to scala-i...@googlegroups.com
On Sun, Oct 21, 2012 at 6:56 PM, Simon Ochsenreither <simon.och...@gmail.com> wrote:
If the rewritten scala.Enumeration isn't compatible with Java enums, why even bother rewriting it? I prefer a useless implementation with known bugs to a useless implementation with unknown bugs.
There is a reason why practically no-one uses scala.Enumeration and "incompatible with the platform' idea of enums" and "buggy" rank pretty high on my list of suspects.

So you don't think it's possible to write less buggy/non buggy code?  Why write anything?

Okay, so, kind of a straw man--I take it that you mean that platform compatibility is an essential requirement for you.
 
Nothing against a bit of NIH, but there is only one valid definition of "enum" and that's the one of the JVM. If the JVM tells me "no, that's not an enum, I won't allow you to use this in an annotation" I don't care about Scala's reason for failing to work as expected.

Reinforced by this point.  If you want Java enums, using Java is a pretty sensible option.  But I don't personally miss being able to stick a Scala Enumeration in a Java annotation.  >90% of my use cases is not creating new annotations.  Unsafe numbering, namespace pollution, ints-only (see classic java "Planets" example for what you can't do in Scala), etc. each chip off a big fraction for me.  I'd be happy to have something better (c.f. "The great is the enemy of the good.").

  --Rex

Simon Ochsenreither

unread,
Oct 21, 2012, 8:09:12 PM10/21/12
to scala-i...@googlegroups.com

If the rewritten scala.Enumeration isn't compatible with Java enums, why even bother rewriting it? I prefer a useless implementation with known bugs to a useless implementation with unknown bugs.
There is a reason why practically no-one uses scala.Enumeration and "incompatible with the platform' idea of enums" and "buggy" rank pretty high on my list of suspects.
So you don't think it's possible to write less buggy/non buggy code?  Why write anything?
My point is that given the constraints it is obvious (imho) that scala.Enumeration can't be fixed to justify its existence, not even remotely.
 
Okay, so, kind of a straw man--I take it that you mean that platform compatibility is an essential requirement for you.
What's the value added by not being compatible with the platform's idea of enums?
 
Nothing against a bit of NIH, but there is only one valid definition of "enum" and that's the one of the JVM. If the JVM tells me "no, that's not an enum, I won't allow you to use this in an annotation" I don't care about Scala's reason for failing to work as expected.
Reinforced by this point.  If you want Java enums, using Java is a pretty sensible option.  But I don't personally miss being able to stick a Scala Enumeration in a Java annotation.  >90% of my use cases is not creating new annotations.
I certainly don't miss scala.Enumeration. It does neither anything well nor anything better than Java enums. It's usage is non-obvious and confusing.

Unsafe numbering, namespace pollution, ints-only (see classic java "Planets" example for what you can't do in Scala), etc. each chip off a big fraction for me.  I'd be happy to have something better (c.f. "The great is the enemy of the good.").
Which of these points is not already adressed by Java enums? How is some, potentially future version of scala.Enumeration improving on what Java's enum did reliably and painfree for the last 8 years? Why or who would want to wait for it at all?
I think the fact that people abandoned scala.Enumeration in favor of integers and fields speaks lengths about the situation. Why not put an end to this suffering, get rid of Scala.Enumeration and give an official blessing to Java enums?

Paul Phillips

unread,
Oct 21, 2012, 9:26:23 PM10/21/12
to scala-i...@googlegroups.com

On Sun, Oct 21, 2012 at 4:34 PM, Rex Kerr <ich...@gmail.com> wrote:
Unsafe numbering, namespace pollution, ints-only

Every scala.Enumeration value having the same erasure, which for most people is a discovery not to be made until after they've boxed themselves in.

scala> object Foo extends scala.Enumeration { val A, B, C = Value }
defined module Foo

scala> object Bar extends scala.Enumeration { val A, B, C = Value }
defined module Bar

scala> def f(x: Foo.Value) = 1 ; def f(x: Bar.Value) = 1
<console>:9: error: double definition:
method f:(x: Bar.Value)Int and
method f:(x: Foo.Value)Int at line 9
have same type after erasure: (x: Enumeration#Value)Int
       def f(x: Foo.Value) = 1 ; def f(x: Bar.Value) = 1
                                     ^

Oleg Galako

unread,
Oct 22, 2012, 2:18:29 AM10/22/12
to scala-i...@googlegroups.com
I think the answer to this will one day come as an independent library (maybe using macros) which will be used by the community. Something like Akka for actors.

Jan Vanek

unread,
Oct 22, 2012, 5:32:58 AM10/22/12
to scala-i...@googlegroups.com
In our project we need to translate the enums - provide texts for the values. In Java what we have to do is to add an extra line into enums, like: 

public enum AddressStatus implements EnumClass<AddressStatus>
{
    ...
    public static final EnumMetaClass<AddressStatus> meta = EnumMetaClass.create(AddressStatus.class, "i18n.app");
}

This is something what can be done much better in Scala. You can't easily add functionality to Java enums. So, to say "just use Java enums" is not a good solution.

Second, we need to customize the enumerated value (add fields, not just one string). This is something you can't do with scala.enum, but with java enum you at least have to write the fields + constructor (assign fields). In Scala this would look nicer.

Third, we don't need complex numbering, built-in ordinal as in Java enum is just fine. Rest is done with fields - constructor params.

So, I took the enum from V. Klang and adapted it to our needs. I think, in the meantime, there exist dozens of house-local enums out there.

My point is, I think there is a need for Scala enum, just not the current one. I mean enum as library, not language built-in.

Regards,
Jan

Josh Suereth

unread,
Oct 22, 2012, 5:39:38 AM10/22/12
to scala-internals

I'd like to chime in on the anti- scala.Enumeration camp.

My point is slightly altered from others:  scala.Enumeration doesn't feel like it belongs in Scala.

If you look at all the other instances of "just a library" for scala, like beakables, actors, futures then you see a nice, elegant abstraction that solves a domain well, is performant at runtime, and "fits" into the language as if it were native.

Enumeration is not.  If you look at its usage pattern it is different from any other thing in the standard library, violates many of the common scala idioms.   While enumerations tend to do this in any language, I think those in Scala's library are a good idea gone poor.

I believe Viktor Klang had a toy replacement that was far more *runtime* safe and performant and unified with case classes.  This I could get behind as more "regular", adding features that feel more natural.   Placing a sealed set of case objects in another object is not as foreign as calling a `Value` method to create one or more instances.  During training we often have to wave our hands here and encourage folks to investigate later.

Here's the crux of the complaint against Enumeration:

(1) toString is not the common way of pulling *data* out of an object (I.e. the name member).
(2) Cannot easily extend enumerated type with additional members.  All new behavior in the containing object.
(3) Implementation practically requires you to use it as top level object, not inside a class or trait.
(4) Does not feel like a set of case object/classes, the major pattern in scala used with pattern matching.

Basically, enumeration always feels like something unnatural, both as a library in the standard, and something the language would support.

I don't even care about java interop here.   I'm not about to say we need compiler support.   However I think the current library is lacking.   If you would entertain improvements, I think we could make them.

If the main goal was avoiding more classes, then perhaps we've succeeded.   However, when I have an ich I want to scratch with enumeration, the current library is a thorny branch, when I just want a nice stick.   I seriously think we should consider improvement here.

Stefan Zeiger

unread,
Oct 22, 2012, 6:55:52 AM10/22/12
to scala-i...@googlegroups.com
On 2012-10-21 22:11, Rex Kerr wrote:
> In practice, between needing byte and short and floating point
> constants, and needing pattern matching, and needing bitmasks for
> which Enumeration generates the wrong progression, I hardly use it at all.

Care to elaborate about the bitmasks? That was one of the main
motivations for switching to the BitSet-based implementation in 2.10.

-sz

martin odersky

unread,
Oct 22, 2012, 8:20:37 AM10/22/12
to scala-i...@googlegroups.com
I am happy to see improvements to enum, of course, and if it requires a different design, that's fine.

There's just one caveat: I really think that enums should be lightweight. One class (or even two) per value is not acceptable. If you are willing to pay that sort of price, it's not too burdensome to just define the case objects directly. Enums fill a different niche: essentially as efficient as integer constants but safer and more convenient to define and to use.

If someone has a design how to make this work better, great!

Cheers

 - Martin

Josh Suereth

unread,
Oct 22, 2012, 8:33:27 AM10/22/12
to scala-i...@googlegroups.com
Sounds like a plan.  I don't think the goal of having minimal enumeration is bad, unless it locks us from improving it.  We have a lot of new vectors of attack we can use, from value classes to macros, and I think Enumeration is ripe for improvement.  If we wall understand the goals:

  • Lightweight, where lightweight = # of classes generated.
  • Typesafe, where one enumeration cannot be passed to another
  • Associates integer id w/ name
I think we could end up with a more "scala" enumeration class given those constraints.

Eugene Burmako

unread,
Oct 22, 2012, 9:03:22 AM10/22/12
to scala-i...@googlegroups.com

I think we can make Enumeration a trait macro, given we empower trait macros to read contents of host classes

On Oct 22, 2012 3:33 PM, "Josh Suereth" <joshua....@gmail.com> wrote:
Sounds like a plan.  I don't think the goal of having minimal enumeration is bad, unless it locks us from improving it.  We have a lot of new vectors of attack we can use, from value classes to macros, and I think Enumeration is ripe for improvement.  If we wall understand the goals:

  • Lightweight, where lightweight = # of classes generated.
  • Typesafe, where one enumeration cannot be passed to another
  • Associates integer id w/ name
I think we could end up with a more "scala" enumeration class given those constraints.



On Mon, Oct 22, 2012 at 8:20 AM, martin odersky <martin....@epfl.ch> wrote:
>

> I am happy to ...

Jan Vanek

unread,
Oct 22, 2012, 9:24:57 AM10/22/12
to scala-i...@googlegroups.com
On Mon, Oct 22, 2012 at 3:03 PM, Eugene Burmako <eugene....@epfl.ch> wrote:

I think we can make Enumeration a trait macro, given we empower trait macros to read contents of host classes

I also thought type macros would be necessary in order to define the fields. Those are not available afaik. However, I thought about how to define the values so that those definition could be seen by the type-macro and perhaps it could use dynamic (likely just dummy to make it compile) calls like this:

object A extend Enum {
  class Value(p1: String, p2: Double)

  // those are dynamic calls:
  A("1", 1)
  B("2", 2)
}

Or do you have a better way in mind?

Regards,
Jan

Eugene Burmako

unread,
Oct 22, 2012, 9:27:19 AM10/22/12
to scala-i...@googlegroups.com
Tbh I don't have any specific encoding of enums for Scala, just proposed type/trait macros as an implementation vehicle, since they might arrive soon.

Speaking of your example, what does A("1", 1) mean?

Jan Vanek

unread,
Oct 22, 2012, 9:33:08 AM10/22/12
to scala-i...@googlegroups.com
A("1", 1) serves to define a value A - instance of Value with p1="1" and p2=2. This "definition" would happen in the type macro, i.e. the result will be:

val A = new Value("1", 1)

But type-macro (I think, I can't know) needs some information to generate such definition, and I thought it could be provided as indicated, where the A("1", 1) would technically be a dynamic call - so that it compiles (well, of course if there is other way to make it compile, then it's better, only I don't know any at the moment).

Regards,
Jan

Eugene Burmako

unread,
Oct 22, 2012, 9:36:18 AM10/22/12
to scala-i...@googlegroups.com
One of the possibilities would be having type macros operating on untyped trees, therefore in thinking about an encoding for enums I wouldn't be too restrained by making stuff typecheck as is. If there's a nice idea that is untyped, we might be able to make it work.

Simon Ochsenreither

unread,
Oct 22, 2012, 9:36:39 AM10/22/12
to scala-i...@googlegroups.com

Tbh I don't have any specific encoding of enums for Scala, just proposed type/trait macros as an implementation vehicle, since they might arrive soon.
 
That's what I proposed, but I think this was shot down already?

Having these means, more or less everything could be done, including inheriting rom java.lang.Enum _and_ allowing people to mix in additional functionality (something you loose when using Java's enums).

But on the other hand, this would amount to having a mini-DSL for enums, because more or less the whole tree would need to be rewritten by the macro.

Simon Ochsenreither

unread,
Oct 22, 2012, 9:40:46 AM10/22/12
to scala-i...@googlegroups.com
I think this would be a good test-case to measure an improvement proposal:

public enum Operation {
  PLUS   { double eval(double x, double y) { return x + y; } },
  MINUS  { double eval(double x, double y) { return x - y; } },
  TIMES  { double eval(double x, double y) { return x * y; } },
  DIVIDE { double eval(double x, double y) { return x / y; } };

  abstract double eval(double x, double y);
}

http://docs.oracle.com/javase/1.5.0/docs/guide/language/enums.html

If someone would manage to make something akin to this work, I would consider some native-Scala enum again.
Until that happens, let's get rid of scala.Enumeration.

Matthew Pocock

unread,
Oct 22, 2012, 10:34:48 AM10/22/12
to scala-i...@googlegroups.com
I have never managed to successfully use scala's enums. I've either ended up reaching for Java enums or fully-fledged sealed traits with case objects. Every time I've tried to use them, I've ended up needing to go back to tutorials and documentation, and fairly quickly found that they don't do what I want, or that every time I refactor things, I have to make a catastrophic change into or out from enums.

Consider the heavy-weight alternative:

sealed trait CompassPoint

object CompassPoint {
  case object North extends CompassPoint
  case object South extends CompassPoint
  case object East extends CompassPoint
  case object West extends CompassPoint
}

This usually gives me more than I need - I don't need North.type and friends, just CompassPoint.North as a unique entity of the same type as South and its other siblings. But, at least it's sealed and scoped, the constants can't be subclassed and are immutable singletons. It's heavy-weight in the amount of code generated. Slightly more light-weight is:

object CompassPoint {
  val North = new CompassPoint
  val South = new CompassPoint
  val East = new CompassPoint
  val West = new CompassPoint
}

However, we need extra boilerplate here so that names work out, and it's easy to do this wrong so that the instances aren't distinguishable according to .hashCode and .equal. In both cases I've had to write separate trait and object, and repeat the trait name all over the place. Eugh!

I guess the point I'm trying to make, in a rambly, unfocussed way, is that I consider scala's enumerations to be unusuable and confusing to the point that I could never recommend that it be used, and would like an alternative that feels like normal scala case class/object hierarchies but with a concise syntax. How about something like:

object CompassPoint {
  case val North
  case val Sourth
  case val East
  case val West
}

This would produce a synthetic, sealed trait CompassPoint, and each case val would be an instance of this. I'm suggesting this as a strawman. Feel free to sprinkle annotations. We have case classes and case objects. For enumerations, it smells like we are groping towards case vals.

Matthew
--
Dr Matthew Pocock
Integrative Bioinformatics Group, School of Computing Science, Newcastle University
skype: matthew.pocock
tel: (0191) 2566550

√iktor Ҡlang

unread,
Oct 22, 2012, 10:37:36 AM10/22/12
to scala-i...@googlegroups.com
This works:

object CompassPoint { val North, South, East, West = new CompassPoint }
--
Viktor Klang

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

Twitter: @viktorklang

Paul Phillips

unread,
Oct 22, 2012, 10:39:27 AM10/22/12
to scala-i...@googlegroups.com


On Mon, Oct 22, 2012 at 7:34 AM, Matthew Pocock <turingate...@gmail.com> wrote:
object CompassPoint {
  val North = new CompassPoint
  val South = new CompassPoint
  val East = new CompassPoint
  val West = new CompassPoint
}

However, we need extra boilerplate here so that names work out, and it's easy to do this wrong so that the instances aren't distinguishable according to .hashCode and .equal. In both cases I've had to write separate trait and object, and repeat the trait name all over the place. Eugh!

Nils Kilden-Pedersen

unread,
Oct 22, 2012, 11:54:12 AM10/22/12
to scala-i...@googlegroups.com
On Mon, Oct 22, 2012 at 4:32 AM, Jan Vanek <j3v...@gmail.com> wrote:
You can't easily add functionality to Java enums.

Sure you can, you can add any method to enum and any abstract method to your enum definition and have the enum values provide an implementation.

 

Jan Vanek

unread,
Oct 22, 2012, 12:08:30 PM10/22/12
to scala-i...@googlegroups.com
Yes, you can do that. What I meant is to add a shared functionality into multiple of enum classes, like e.g. support for translation. To do that nicely requires extending a "base enum" class from which your concrete enums will inherit. But you can't extend enums in Java.

Regards,
Jan

Jan Vanek

unread,
Oct 22, 2012, 12:46:22 PM10/22/12
to scala-i...@googlegroups.com
OK, I imagine something like this:

In Scala library there something like this (I only write the interface), I don't know how the macro type will look like:

  trait Enumeration extends Serializable {
    type Value <: Enumerated

    trait Enumerated extends Serializable {
      val ordinal: Int
      val name: String
    }

    def values: Seq[Value]
  }

Someone might need to customize the enums, so he/she writes this:

  trait MyEnumeration(resourceBundle: String) extends Enumeration {
    type Value <: Enumerated

    trait Enumerated extends super.Enumerated {
      def text = "get from resource bundle"
    }
  }

Concrete enums are always objects. Example 1:

  object Status extends MyEnumeration("i18n/xy") {
    // generated
    // type Value = Status

    // generated
    // private class ValueImpl(val ordinal: Int, val name: String) extends Value

    RUNNING
    FINISHED

    // generated
    // val RUNNING: Value = new ValueImpl(0, "RUNNING")
    // val FINISHED: Value = new ValueImpl(1, "FINISHED")
  }

  // generated
  // abstract class Status extends Status.Enumerated

Simon's example which however requires a class per value.

  object Operation extends Enumeration {
    // generated
    // type Value = Operation

    // generated
    // private abstract class ValueImpl(val ordinal: Int, val name: String) extends Value

    PLUS { def eval(x: Double, y: Double) = x + y }

    // generated:
    // val PLUS: Value = new ValueImpl(0, "PLUS") { def eval(x: Double, y: Double) = x + y }
  }

  // not generated, have to write

  trait Operation extends Operation.Enumerated {
    def eval(x: Double, y: Double): Double
  }

I don't know whether macro types could generate "companion" classes. Also, the macro should "trigger" only in object, not in the custom MyEnumeration. This might not work, you know better.

Also, I didn't insert the values into the values collection in base Enumerated, but that should be doable. Also, I didn't attempt to implement the serialization stuff, like writeReplace/readResolve - however it has been done and once I did a modification to account for whether the enum is top-level object or not.

Regards,
Jan

Rex Kerr

unread,
Oct 22, 2012, 1:13:20 PM10/22/12
to scala-i...@googlegroups.com

val ForwardFlag = 0x01
val OccupiedFlag = 0x02
val UpdatedFlag = 0x04
val ArrayBackedFlag = 0x08
val ExtraFlag = 0x10
...

vs

object Flags extends Enumeration { ??? }

  --Rex

Jan Vanek

unread,
Oct 22, 2012, 2:11:23 PM10/22/12
to scala-i...@googlegroups.com
object Flag extends Enumeration {
  Forward
  Occupied
  Updated
  ArrayBacked
  Extra
}

trait Flag extends Flag.Enumerated {
  val value = 1 << ordinal
}

Is this too heavyweight for your requirements?

With regards,
Jan

P.S. Sorry about mentioning that we don't need complex numbering in our project.

Som Snytt

unread,
Oct 22, 2012, 2:33:22 PM10/22/12
to scala-i...@googlegroups.com
Perhaps this isn't -internals fodder anymore, and I apologize for opening this can of worms, which turned out to be one of those party favors from which a huge snake springs and causes a big ruckus.

I was curious about the bit mask use case, so here is my finger exercise.  No DIE.

For the record, paulp is the reason I align my assignment operators (after all these years).  Scala has brought so much good into the world.

package mixer

import scala.language.implicitConversions

object colors extends Enumeration {
  trait Color {
    def bits: Int
    def isPrimary: Boolean
  }
  implicit def asColor(v: Value) = v.asInstanceOf[Color]
  implicit class Primarily(val mask: Array[Long]) extends AnyVal {
    def toPrimaryMask: Int = {
      val ps = colors.values filter (_.isPrimary)
      val pbits = ps.toBitMask(0).toInt
      mask(0).toInt & pbits
    }
  }
  class Primary extends Val with Color {
    def bits = ValueSet(this).toBitMask.toPrimaryMask
    def isPrimary = true
  }
  class Secondary(p1: Primary, p2: Primary) extends Val with Color {
    def bits = (p1 + p2).toBitMask.toPrimaryMask
    def isPrimary = false
  }
  val Red, Blue = new Primary
  val Purple    = new Secondary(Red, Blue)    // in this position, consumes a bit
  val Yellow    = new Primary
  val Green     = new Secondary(Blue, Yellow)
}

object Test extends App {
  import colors._
  println(s"${Red.bits} are red, ${Blue.bits} are blue")
  println(s"${Purple.bits} are purple, and so are you")
  println(s"Luck of the Irish, wearin' o' the green: ${Green.bits}")

Nils Kilden-Pedersen

unread,
Oct 22, 2012, 3:33:21 PM10/22/12
to scala-i...@googlegroups.com
On Mon, Oct 22, 2012 at 1:11 PM, Jan Vanek <j3v...@gmail.com> wrote:
object Flag extends Enumeration {
  Forward
  Occupied
  Updated
  ArrayBacked
  Extra
}

trait Flag extends Flag.Enumerated {
  val value = 1 << ordinal
}

What happens when you run out of bits, which doesn't take long?

Eugene Burmako

unread,
Oct 22, 2012, 4:44:42 PM10/22/12
to scala-i...@googlegroups.com
Nice pun :)

Jan Vanek

unread,
Oct 22, 2012, 4:56:54 PM10/22/12
to scala-i...@googlegroups.com
On 22.10.2012 20:33, Som Snytt wrote:
Perhaps this isn't -internals fodder anymore, and I apologize for opening this can of worms, which turned out to be one of those party favors from which a huge snake springs and causes a big ruckus.

I was curious about the bit mask use case, so here is my finger exercise.  No DIE.

You're right, my scheme can't encode two/more internal sub-classes of such an enum. Two/more constructors is possible, but that is not good enough for you. Something better is needed.

Rex Kerr

unread,
Oct 22, 2012, 5:24:40 PM10/22/12
to scala-i...@googlegroups.com
Er, this is some weird hybrid of Java enums and Scala Enumeration.  That might be okay, but it's not available now.

  --Rex

Havoc Pennington

unread,
Oct 22, 2012, 5:45:00 PM10/22/12
to scala-i...@googlegroups.com
On Mon, Oct 22, 2012 at 8:33 AM, Josh Suereth <joshua....@gmail.com> wrote:
Sounds like a plan.  I don't think the goal of having minimal enumeration is bad, unless it locks us from improving it.  We have a lot of new vectors of attack we can use, from value classes to macros, and I think Enumeration is ripe for improvement.  If we wall understand the goals:

  • Lightweight, where lightweight = # of classes generated.
  • Typesafe, where one enumeration cannot be passed to another
  • Associates integer id w/ name
I think we could end up with a more "scala" enumeration class given those constraints.


Using an enumeration class like that sure would feel like premature optimization much of the time (vs. a sealed trait with case objects). If we already have both Java enums and case objects, now we're adding a third alternative which is called enum, but normally if you wanted a Java enum you should really use case objects ... kind of a pesky thing to explain to people.

Havoc

Paul Phillips

unread,
Oct 22, 2012, 6:38:49 PM10/22/12
to scala-i...@googlegroups.com
For the syntactic thing with case objects, which does annoy, I wonder if we could gift ourselves

  case object Monday, Tuesday, Wednesday, Thursday, Friday extend Weekday

It's not exactly out of left field given the existence of

  val Monday, Tuesday, Wednesday, Thursday, Friday = new Weekday


Jan Vanek

unread,
Oct 22, 2012, 9:56:02 PM10/22/12
to scala-i...@googlegroups.com
I think the proposed scheme could be changed (keeping all the extension points) so that a Java enum can be generated. We would still have the proprietary companion object extending the Enumeration/CustomEnumeration and the generated enum would implement the Enumerated trait. The Enumerated would have to remain a trait, so adding new fields would have to be done like:


object Status extends MyEnumeration("i18n/xy") {
  trait Enumerated extends super.Enumerated {
     val p1: String
     val p2: Int

     def eval(x: Double, y: Double): Double
     val flag = 1L << ordinal
  }

  RUNNING("out of bits", 0x01) { def eval(x: Double, y: Double) = x + y }
  FINISHED("now", 0xFF) { def eval(x: Double, y: Double) = x * y }
}

This means no extra constructors, the type-macro would infer the constructor needs p1 and p2, and no other are allowed. Also the Status class will be strictly generated.

This doesn't solve Som's requirement to have two/more sub-classes within one enum. And I don't know anymore whether generating java enum is the real goal.

Good night,
Jan

nafg

unread,
Oct 22, 2012, 10:16:30 PM10/22/12
to scala-i...@googlegroups.com

On Sunday, October 21, 2012 4:11:17 PM UTC-4, Rex Kerr wrote:
and allows (at compile-time) but breaks on repeated values (numeric constants allow repeats and do not break):

 Regarding the lack of compile-time safety, can that be solved by making def Value (or is it Value.apply?) a macro? Let it cache the values and generate a compile error if it finds a duplicate.

nafg

unread,
Oct 22, 2012, 10:24:20 PM10/22/12
to scala-i...@googlegroups.com
+1!

(Although it may need to be extends...)

Paul Phillips

unread,
Oct 22, 2012, 10:57:05 PM10/22/12
to scala-i...@googlegroups.com


On Mon, Oct 22, 2012 at 7:24 PM, nafg <nafto...@gmail.com> wrote:
(Although it may need to be extends...)

Oops, the subconscious grammar pedant overrode the intention.  I meant to type extends.

Paul Phillips

unread,
Oct 22, 2012, 10:57:25 PM10/22/12
to scala-i...@googlegroups.com
On Mon, Oct 22, 2012 at 7:57 PM, Paul Phillips <pa...@improving.org> wrote:
Oops, the subconscious grammar pedant overrode the intention.  I meant to type extends.

At least I managed not to write "case objects Monday, Tuesday..." 

Stefan Zeiger

unread,
Oct 23, 2012, 6:09:43 AM10/23/12
to scala-i...@googlegroups.com
I still don't follow.

  object Flags extends Enumeration {
    val Forward, Occupied, Updated, ArrayBacked, Extra = Value
  }
 
  println((Flags.Forward + Flags.Updated).toBitMask(0))

  def isForwardOccupied(l: Long) =
    (Flags.Forward + Flags.Occupied) subsetOf Flags.ValueSet.fromBitMask(Array(l))


  val ForwardFlag = 0x01
  val OccupiedFlag = 0x02
  val UpdatedFlag = 0x04
  val ArrayBackedFlag = 0x08
  val ExtraFlag = 0x10

  println(isForwardOccupied(ForwardFlag | UpdatedFlag))
  println(isForwardOccupied(ForwardFlag | OccupiedFlag | ExtraFlag))

  println(Flags.ValueSet.fromBitMask(Array(OccupiedFlag | UpdatedFlag)))

This prints:

  5
  false
  true
  Flags.ValueSet(Occupied, Updated)

Everything's nicely interoperable.

-sz

martin odersky

unread,
Oct 23, 2012, 6:25:45 AM10/23/12
to scala-i...@googlegroups.com
That's easy to do. But I'd only do it if at the same time we can ensure that we do not generate 2 classes for each object. Number of classes need to stay constant, no matter how many objects you define. That last one seems a bit trickier to achieve, because you still want enum constants to print their name with toString.

Cheers

 - Martin


 

Rex Kerr

unread,
Oct 23, 2012, 6:40:43 AM10/23/12
to scala-i...@googlegroups.com
I'm not saying that there are no facilities for dealing with bitmasks.  But if enums are for creating useful constants, this method requires considerable extra boilerplate if you actually need to get at the bitmask value.  If I have to
  Flags.ValueSet(Flags.Forward).toBitMask(0)
instead of
  Flags.Forward
every time I want to use a bitmask, I don't think I'm going to be particularly inclined to use Enumeration rather than val Forward = 0x1.  It's three times as much typing, I have four conceptual steps instead of one, and I create two temporary objects instead of doing a field access.  No thanks!

  --Rex

Simon Ochsenreither

unread,
Oct 23, 2012, 9:56:11 AM10/23/12
to scala-i...@googlegroups.com

And I don't know anymore whether generating java enum is the real goal.

I would say it is at least one of the goals. I have nothing against innovation, but I think it makes sense to start from an established implementation. Additionally, being incompatible with Java enums doesn't buy us anything but costs us a lot.

Imho the right way would be do start with a type macro to do the necessary magic of synthesizing the required superclass and methods, and let people add additional functionality with bog-standard traits.

Simon Ochsenreither

unread,
Dec 3, 2013, 10:12:24 PM12/3/13
to scala-i...@googlegroups.com
I'm happy to report that I managed to make a lot of progress (of course with tons of help by other people)!

Enum definition:

@enum
class Day {
  Monday
  Tuesday
  Wednesday
  Thursday
  Friday
  Saturday
  Sunday
}


Enum usage:

// Using enums in annotations works
public @interface DayAnnotation {
  // It's Friday, Friday
  Day bestDay() default Day.Friday;
}

// Some code:
@DayAnnotation(bestDay = Day.Monday) // annotation works
public class JavaDayConsumer {
    public static void main(String[] args) {
    System.out.println("Day.Monday");
    System.out.println(Day.Monday); // All the needed public static final fields exist
    System.out.println("Day.values()"); // The values() method exists and is correctly populated
    for (Day day : Day.values()) {
        System.out.println(day);
    }
    System.out.println("Day.valueOf(\"Monday\")"); // The valueOf(String) method works
    Day monday = Day.valueOf("Monday");
    System.out.println(monday);
    }
}


Output:

Day.Monday
Monday
Day.values()
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
Day.valueOf("Monday")
Monday


What's missing is support form Scala (shouldn't be too hard). Scala doesn't see the value Day, because I'm not generating a companion object and I guess scalac doesn't look for static methods inside of classes defined in Scala yet.

Rich Oliver

unread,
Dec 4, 2013, 3:39:39 PM12/4/13
to scala-i...@googlegroups.com
So currently we have:

Scala Enums: broken
Java Enums: Ugly, plus farming out syntax to Java is well just naff
Sealed Class and Objects: The Scala way but a lot of ceremony
Boolean: Horrendously unsafe. Booleans should only be used where there is some serious performance justification.

Paul's suggestion seems on the correct track, reduce the ceremony for Sealed Class and Objects. Depreciate Scala Enums and discourage the use of Java Enums and Boolean. That would be a grand simplificaton.


On Monday, October 22, 2012 11:38:51 PM UTC+1, Paul Phillips wrote:
For the syntactic thing with case objects, which does annoy, I wonder if we could gift ourselves

  case object Monday, Tuesday, Wednesday, Thursday, Friday extend Weekday
 
Other thoughts:

Why not just


object Monday, Tuesday, Wednesday, Thursday, Friday extend Weekday

Would Weekday be automatically sealed? Presumably toString methods for the objects would automatically be created. Would an iterator over the weekday objects be automatically created in the Weekday class?

Simon Ochsenreither

unread,
Jan 17, 2014, 7:15:55 PM1/17/14
to scala-i...@googlegroups.com
@enum
class DayConstructors(val abbr: String) {
  Monday("Mon")
  Tuesday("Tue")
  Wednesday("Wed")
  Thursday("Thu")
  Friday("Fri")
  Saturday("Sat")
  Sunday("Sun")
}

public class DayConstructorsConsumer {

    public static void main(String[] args) {
        System.out.println("Day.Monday");
        System.out.println(DayConstructors.Monday);
        System.out.println("Day.values()");
        for (DayConstructors day : DayConstructors.values()) {

            System.out.println(day);
        }
        System.out.println("Day.valueOf(\"Monday\")");
        DayConstructors monday = DayConstructors.valueOf("Monday");
        System.out.println(monday);
        System.out.println("Day.Monday.abbr()");
        System.out.println(monday.abbr());

    }
}

Day.Monday
Monday
Day.values()
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
Day.valueOf("Monday")
Monday
Day.Monday.abbr()
Mon

Rex Kerr

unread,
Jan 17, 2014, 7:28:16 PM1/17/14
to scala-i...@googlegroups.com
That is looking very much like something I would like to use!  But what about

  (dc: DayConstructors) match {
    case Monday(_) =>
    case Tuesday(_) =>
  }
  // warning on missing cases
  ?

--Rex



--
You received this message because you are subscribed to the Google Groups "scala-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-interna...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Simon Ochsenreither

unread,
Jan 18, 2014, 1:28:58 PM1/18/14
to scala-i...@googlegroups.com

  (dc: DayConstructors) match {
    case Monday(_) =>
    case Tuesday(_) =>
  }


Yes, better pattern matching works. I'm automatically generating the necessary unapply methods when appropriate now:

@enum class Day(val abbreviation: String, val isWeekend: Boolean) { ... }

val Day(abbr, weekend) = monday
println(abbr)
println(weekend)


[info] Running scalax.ScalaDayUnapplyConsumer
Mon
false

 
  // warning on missing cases

Given that I create just ordinary Java enums, exhaustiveness checks should already work.

Francois Armand

unread,
Jan 19, 2014, 4:20:22 AM1/19/14
to scala-i...@googlegroups.com

Just wow! That's enum I want!

--

Naftoli Gugenheim

unread,
Jan 19, 2014, 5:03:53 AM1/19/14
to scala-internals
Very exciting!

Are there rules as to what other statements you're allowed to write inside an @enum?



--
You received this message because you are subscribed to the Google Groups "scala-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-interna...@googlegroups.com.

Simon Ochsenreither

unread,
Jan 19, 2014, 9:11:04 AM1/19/14
to scala-i...@googlegroups.com

Very exciting!

Are there rules as to what other statements you're allowed to write inside an @enum?

Pretty much no. I assumed that Java disallowed inner classes and stuff, but it doesn't. So I won't disallow that either.

The only important rule is that the enum elements must come first in the class body.

virtualeyes

unread,
Jan 19, 2014, 4:52:38 PM1/19/14
to scala-i...@googlegroups.com
How do a sign up?

Or, when will this make it in into Scala-land?

Pretty awesome work, have avoided Scala enums in favor of Java enums and sealed trait/case objects

Simon Ochsenreither

unread,
Jan 19, 2014, 5:56:42 PM1/19/14
to scala-i...@googlegroups.com
Hi!


How do a sign up?
Or, when will this make it in into Scala-land?

I hope so. I'm currently planning to propose a SIP for 2.12 (debate here: https://groups.google.com/d/topic/scala-sips/Bf82LxK02Kk/discussion), but there are certain things which I can't influence:
  • I'm not the one making decisions
  • This depends on macro annotations, which are not (yet) in trunk

Regarding the second point: The alternative would be to include the code in the compiler until Scala trunk gets macro annotations and then factor it out again later. But I really hope to have macro annotations shipping (as experimental) in 2.12. We have tons of work to do to catch up to F# type providers, and delaying it for another version would be a terrible mistake imho.

Thanks!

Simon


PS: I just updated the spec: https://docs.google.com/document/d/1mIKml4sJzezL_-iDJMmcAKmavHb9axjYJos_7UMlWJ8

virtualeyes

unread,
Jan 20, 2014, 3:28:34 AM1/20/14
to scala-i...@googlegroups.com
Agreed re: catching up to F# type providers; that would be a huge win for Scala, and adoption of Slick in particular (where modeling boilerplate still reigns).

While streamlining the language is a worthy (and necessary) goal, competition is coming >> Java 8, Kotlin, and Ceylon, as well as Clojure and Groovy.

2.12 should then be leaner and (somehow) more powerful in order to remain a cut above the rest.

p.s. your enum implementation removes the cermony of sealed class/case objects while adding in additional functionality, totally brilliant, you've managed to implement clobjects (case class + case objects), really hope this makes it in to 2.12.

Grzegorz Kossakowski

unread,
Jan 20, 2014, 4:20:19 AM1/20/14
to scala-internals
On 19 January 2014 23:56, Simon Ochsenreither <simon.och...@gmail.com> wrote:
  • This depends on macro annotations, which are not (yet) in trunk

Regarding the second point: The alternative would be to include the code in the compiler until Scala trunk gets macro annotations and then factor it out again later. But I really hope to have macro annotations shipping (as experimental) in 2.12. We have tons of work to do to catch up to F# type providers, and delaying it for another version would be a terrible mistake imho.

Decision whether to declare some feature as stable is driven by assessing technical matureness of it. The reality is that even blackbox macros, the simplest flavor of macors, is still not mature enough to be declared stable. I think we should channel our energy into stabilizing and refining what we already have before we start merging new features. That's how I'll vote if the time comes to make a decision.

--
Grzegorz Kossakowski
Scalac hacker at Typesafe
twitter: @gkossakowski

Simon Ochsenreither

unread,
Jan 20, 2014, 11:10:52 AM1/20/14
to scala-i...@googlegroups.com

Decision whether to declare some feature as stable is driven by assessing technical matureness of it. The reality is that even blackbox macros, the simplest flavor of macors, is still not mature enough to be declared stable. I think we should channel our energy into stabilizing and refining what we already have before we start merging new features. That's how I'll vote if the time comes to make a decision.

I can understand your reasoning and normally I would side with you on this, but let me explain why I disagree in this specific case:
  • Is there any potential that beginners run into building a macro "accidentally" and end up confused? I'd say absolutely no!
  • Technical maturity comes from people using those things in anger. Relegating it to "a prototype of an experimental feature available via a compiler plugin" drastically reduces the amount of people who are willing to look into it, because it makes it much harder to ship things depending on it.
  • Not everyone cares about the same macro flavors. Making it harder for people to build things on macro annotations, won't make macro methods more stable. Most people are volunteers; we can't force them to work on/test the things we want. That's just demotivating for them. Personally, I don't care much about building macro methods, they are just not useful for the things I want to build.
  • I really think we are missing the boat here, if we wait for yet another version. Sometimes, timing is crucial, and the window of opportunity is rapidly closing.
    Things like type providers would be an important way to demonstrate to skeptic developers that all the work and power we put into the types and the compiler finally bears fruits and set us apart from those copy-cat languages which have been emerging lately.
  • There are already important libraries which are basically waiting for macro annotations: Look at Slick, and their current stop-gap solution of generating source code. I really hope they don't have to deal with all the complexity of that forever, so it would be great if that approach is really just a transitional solution and not something they have to develop for the next few years.

Therefore, I'd really prefer to give the macro styles which seem to be conceptually valid (macro methods, macro annotations, "macro typeclasses" (can't remember what it was called)) the opportunity to evolve at their own speed.
This means allowing them to mature and stabilize in parallel, instead of forcing a sequential model where we can only start working for real on "B" if "A" is done.

By making it easier to build things with them, we will get helpful feedback earlier and faster.

Jason Zaugg

unread,
Jan 20, 2014, 11:35:18 AM1/20/14
to scala-i...@googlegroups.com
On Mon, Jan 20, 2014 at 5:10 PM, Simon Ochsenreither <simon.och...@gmail.com> wrote:
  • There are already important libraries which are basically waiting for macro annotations: Look at Slick, and their current stop-gap solution of generating source code. I really hope they don't have to deal with all the complexity of that forever, so it would be great if that approach is really just a transitional solution and not something they have to develop for the next few years.
I'd like to point out that this stop-gap solution does have *some* nice properties: it is well understood, one can control when it happens and checkin the results, and it works well with IDE completion/navigation.

Therefore, I'd really prefer to give the macro styles which seem to be conceptually valid (macro methods, macro annotations, "macro typeclasses" (can't remember what it was called)) the opportunity to evolve at their own speed.
This means allowing them to mature and stabilize in parallel, instead of forcing a sequential model where we can only start working for real on "B" if "A" is done.

By making it easier to build things with them, we will get helpful feedback earlier and faster.

We've added the hooks into the compiler so that Eugene's latest work is available for early adopters in macro paradise. I think this strikes a good balance: we making research available while sending a clear signal about its status.

We're only just getting the Scala IDE to play nicely with macros of any flavour. Anything other than blackbox macros leads to a sub-par experiments in the IDE; IntelliJ can't handle it at all, and while Scala IDE can, it won't be able to in the new mode we're working on that lets you install a 2.11 IDE and use that for 2.10 projects as well.

I would really prefer that we focus on making macro author's job significantly easier before we open the gate further. Most macro implementations that I review are riddled with hygiene/ref-transparency problems. To that end, Denys is researching ways to tackle the enormous difficulty one faces in assembling trees conveniently and safely. Quasiquotes helps on the first point, but not the second.

Stepping back a little, we have to balance our investment into macros and reflection against our other goals for the language. This year, we want to focus on the backend (switching to GenBCode, Java8-style lambdas, and maybe defender methods for traits), continue to improve general quality of the library and compiler, and work towards better static analysis tools to complement the compiler. And we have to do this with a smaller team than we had last year.

-jason

Hanns Holger Rutz

unread,
Jan 20, 2014, 11:48:14 AM1/20/14
to scala-i...@googlegroups.com
In any case, it would be good to recall Eugene Burmako's remarks on
Whitebox macros in the Strangeloop presentation:
http://www.infoq.com/presentations/scala-macros

E.g. "Whitebox is not very Scala", from around 34:21", which features
more or less the same enum construction.

While I think it's totally great to have macro annotations, I am not
sure that introducing a quasi standard language element based on them
which comes with new "magic" really helps the perception of Scala being
a very "regular" language...

2c, .h.h.



On 20/01/2014 17:35, Jason Zaugg wrote:
> On Mon, Jan 20, 2014 at 5:10 PM, Simon Ochsenreither
> <simon.och...@gmail.com <mailto:simon.och...@gmail.com>>
> wrote:
>
> * There are already important libraries which are basically
> waiting for macro annotations: Look at Slick, and their current
> stop-gap solution of generating source code. I really hope they
> don't have to deal with all the complexity of that forever, so
> it would be great if that approach is really just a transitional
> solution and not something they have to develop for the next few
> years.
>
> I'd like to point out that this stop-gap solution does have *some* nice
> properties: it is well understood, one can control when it happens and
> checkin the results, and it works well with IDE completion/navigation.
>
> Therefore, I'd really prefer to give the macro styles which seem to
> be conceptually valid (macro methods, macro annotations, "macro
> typeclasses" (can't remember what it was called)) the opportunity to
> evolve at their own speed.
> This means allowing them to mature and stabilize in parallel,
> instead of forcing a sequential model where we can only start
> working for real on "B" if "A" is done.
>
> By making it easier to build things with them, we will get helpful
> feedback earlier and faster.
>
> We've added the hooks into the compiler so that Eugene's latest work is
> available for early adopters in macro paradise. I think this strikes a
> good balance: we making research available while sending a clear signal
> about its status.
>
> We're only just getting the Scala IDE to play nicely
> <http://assembla.com/spaces/scala-ide/tickets/1001449> with macros of
> any flavour. Anything other than blackbox macros leads to a sub-par
> experiments in the IDE; IntelliJ can't handle it at all, and while Scala
> IDE can, it won't be able to in the new mode we're working on that lets
> you install a 2.11 IDE and use that for 2.10 projects as well.
>
> I would really prefer that we focus on making macro author's job
> significantly easier before we open the gate further. Most macro
> implementations that I review are riddled with hygiene/ref-transparency
> problems. To that end, Denys is researching ways to tackle the enormous
> difficulty one faces in assembling trees conveniently and safely.
> Quasiquotes helps on the first point, but not the second.
>
> Stepping back a little, we have to balance our investment into macros
> and reflection against our other goals for the language. This year, we
> want to focus on the backend (switching to GenBCode, Java8-style
> lambdas, and maybe defender methods for traits), continue to improve
> general quality of the library and compiler, and work towards better
> static analysis tools to complement the compiler. And we have to do this
> with a smaller team than we had last year.
>
> -jason
>

Kevin Wright

unread,
Jan 20, 2014, 12:16:04 PM1/20/14
to scala-internals
On 20 January 2014 16:48, Hanns Holger Rutz <con...@sciss.de> wrote:
In any case, it would be good to recall Eugene Burmako's remarks on
Whitebox macros in the Strangeloop presentation:
http://www.infoq.com/presentations/scala-macros

E.g. "Whitebox is not very Scala", from around 34:21", which features
more or less the same enum construction.

 
While I think it's totally great to have macro annotations, I am not
sure that introducing a quasi standard language element based on them
which comes with new "magic" really helps the perception of Scala being
a very "regular" language...

That's as maybe, but it does have a *significant* perception on Scala being perceived as a Java-compatible language.

If you've ever attempted any automated-conversion of Java->Scala then you'll know that enums are the pain-point, they just choke up the conversion (at least, they did the last time I tried this in intellij)

Likewise, if you've ever wanted to produce a Scala library for consumption within native Java, and an enum would be the "obvious" solution in your API; then you're stuck having to implement them in Java.

enums are a standard construct on the JVM, they're extensively used in the wild, and it *is* a problem that Scala can't provide them.  However "quasi" you believe them to be, they're a widely accepted standard and we can't simply pretend that they don't exist.


The alternatives we have available are poor choices in many scenarios.  An algebraic type (sealed trait + subclasses) is heavyweight in terms of classes, which can cause problems for e.g. Android projects.  Scala's own Enumeration type is at least more lightweight, but it's clumsy to use and comes with other problems (including Java compatibility)


One way or another, Simon's right.  This is a much-needed feature with a lot of demand and some clear-cut use-cases for which there is no realistic alternative.

Hanns Holger Rutz

unread,
Jan 20, 2014, 12:21:41 PM1/20/14
to scala-i...@googlegroups.com
I never said that.

I am saying, if enums are so important for life and java interop, then
perhaps they be better defined in the language spec instead of using a
macro.

Eugene Burmako

unread,
Jan 20, 2014, 12:27:59 PM1/20/14
to <scala-internals@googlegroups.com>
On the other hand, one of the direct reasons to introduce macros was the fact that they let us cut down language features.


Kevin Wright

unread,
Jan 20, 2014, 12:29:16 PM1/20/14
to scala-internals

Wrong direction... There's an even more pressing need to simplify and stabilise the core compiler.

Right now it's carrying a lot of baggage that slows down new development and makes it hard to old bugs without introducing new ones.  Get macros right and some compiler logic can be moved into the library.  That's a win for binary compatibility, a win for stability, and a win for the pace of adding new features.

Eugene Burmako

unread,
Jan 20, 2014, 1:00:56 PM1/20/14
to <scala-internals@googlegroups.com>, Simon Ochsenreither
Just to provide a bit more background about the talk.

@Enum slides at StrangeLoop summarize the discussion about Simon's macro annotation that was available even before the talk. (Actually I was very surprised that I didn't link to that discussion - sorry, Simon! Now it's fixed, at least in the downloadable pdf, which I'm going to submit as a PR to the STL's site, from where it will hopefully propagate to infoq.)

What I wanted to say back then (and what I still think) is that Simon's notation is a bit too extravagant, but I have a feeling that neither macro annotations, nor the @Enum macro have fundamental problems. I believe that further experiments will provide more insight on how to provide some sort of signatures for macro annotations, which seems to be the only missing point now. That's why I'm happy to provide continuous support for macro annotations in macro paradise, and that's why I'm very grateful to Simon for contributing to the experiments.

Also, from the standpoint of compiler internals, macro annotations are quite important, as they show a working mechanism of hooking into namer, being as untyped as necessary and as typed as possible. This opens the doors to a number of related techniques that I'm hoping to explore in more detail once I'm finished with the current bunch of ideas.


Hanns Holger Rutz

unread,
Jan 20, 2014, 1:12:41 PM1/20/14
to scala-i...@googlegroups.com
Thanks for your remarks, Eugene. Again, not to be misunderstood, I find
macro paradise an incredibly cool project and I'm all for research, and
I'm happy that macro annotations preserve some of the possibilities that
otherwise would require type macros (indeed I'm trying to experiment
with macro annotations, although I haven't had enough time yet). In
general, having macros in Scala really lowers the bar for experiments
which had previously required that you study the compiler internals to
write custom compiler plugins.

But given that "Understanding Scala Enumerations" is one of the most
looked up Stackoverflow question
(http://stackoverflow.com/questions/11067396/understanding-scala-enumerations/),
where obviously `val Mon, Tue, Wed, ... = Value` is already hardly
understandable by most people (I remember I was also stunned), I thought
it would be good to remain critical with syntax such as `@enum class
Day(val abbreviation: String) { Monday("Mon"); Tuesday("Tue") ... }`
being absolutely intuitive to everyone.

best, .h.h.

Kevin Wright

unread,
Jan 20, 2014, 1:22:29 PM1/20/14
to scala-internals

given that "Understanding Scala Enumerations" is one of the most
looked up Stackoverflow question
(http://stackoverflow.com/questions/11067396/understanding-scala-enumerations/),
where obviously `val Mon, Tue, Wed, ... = Value` is already hardly
understandable by most people (I remember I was also stunned), I thought
it would be good to remain critical with syntax such as `@enum class
Day(val abbreviation: String) { Monday("Mon"); Tuesday("Tue") ... }`
being absolutely intuitive to everyone.

I strongly suspect that the exact opposite will happen.

Arguably the main use-case for @enum is Java interop, which Simon's proposed syntax mirrors almost exactly.
Anyone coming from Java or trying to provide an API for Java consumption will have absolutely no problem with this whatsoever.

Dig a bit deeper, and you'll find that the vast majority of enum-hunters on StackOverflow are the Java ex-pats, exactly the same people for whom this syntax will be intimately familiar.

A bigger problem, if anything, will be over-use/abuse of the facility by that group; where people will stick to their comfort zone instead of exploring more appropriate/idiomatic styles.
I already fear the potential (time) cost of overused macro expansion here, and the looming question "I wrote my Scala code almost exactly like my Java code with @enum, and it's slow to compile, why?"

 

Eugene Burmako

unread,
Jan 20, 2014, 1:27:07 PM1/20/14
to <scala-internals@googlegroups.com>
What would make @enum-using code slow to compile?


--

Eugene Burmako

unread,
Jan 20, 2014, 1:33:52 PM1/20/14
to <scala-internals@googlegroups.com>, Simon Ochsenreither
Speaking of syntax. From what I understand, at the moment enum-paradise features the following syntax for the days of week example:

@Enum
class Days(val inGerman: String) extends HasName {
  Monday("Montag")
  Tuesday("Dienstag")
  Wednesday("Mittwoch")
  Thursday("Donnerstag")
  Friday("Freitag")
  Saturday("Samstag") { override def workingDay: Boolean = false },
  Sunday("Sonntag") { override def workingDay: Boolean = false }

  def abbreviation = name take 3
  def workingDay: Boolean = true
}

Would it be make sense to have something along these lines? Would it support all the required features?

class Days(val inGerman: String) extends HasName {
  def abbreviation = name take 3
  def workingDay: Boolean = true
}

@Enum
object Days {
  val Monday = new Day("Montag")
  val Tuesday = new Day("Dienstag")
  val Wednesday = new Day("Mittwoch")
  val Thursday = new Day("Donnerstag")
  val Friday = new Day("Freitag")
  val Saturday = new Day("Samstag") { override def workingDay: Boolean = false }
  val Sunday = new Day("Sonntag") { override def workingDay: Boolean = false }
}

In the light of the previous discussion, what I find appealing about this version is that is provides all the key bindings as-is (e.g. Days's methods end up being methods on Days, Days's fields end up being static fields, etc.). Sure, there is magic going on (like Days inheriting java.lang.Enum or Days getting values and valueOf), but the same kind of stuff happens with case classes, and it's not like we are unhappy about it. If that works out, I think it would be possible to come up with a mechanism that says "this annotation doesn't touch existing bindings, and only adds this, that and that", which should make things self-evident.



Rex Kerr

unread,
Jan 20, 2014, 3:09:36 PM1/20/14
to scala-i...@googlegroups.com, Simon Ochsenreither
As a user of enums, I strongly prefer Simon's syntax to the lots-of-extra-boilerplate syntax.

Part of the point of enums is that you've got a lot of boring work to do.  The easier you can make it, the better.  The more powerful the better, also--Rust, for example, combines both super-easy enumeration and union types into one reasonably coherent enum concept.

It's fine to have a less sugared version too, but I'd like my enums sweet, please.

  --Rex


Lukas Rytz

unread,
Jan 20, 2014, 3:33:24 PM1/20/14
to scala-i...@googlegroups.com, Simon Ochsenreither
So Martin is against built-in enumerations to keep the language smaller. Now people
seem to agree that a macro based solution would fix this dilemma.

I think this is only half of the truth. Having language features live outside the spec as macros
also comes with a cost (e.g., IntelliJ), and they don't make the language smaller in terms of
mental overhead for the user.

Eugene Burmako

unread,
Jan 20, 2014, 3:39:42 PM1/20/14
to <scala-internals@googlegroups.com>, Simon Ochsenreither
Indeed, the current implementation of macros has limitations, but let's temporarily think past them. What are the costs of having language features implemented as macros? Given the ideal world, would it be possible to address these costs? For one, would better IDE support would ameliorate the costs?

Rex Kerr

unread,
Jan 20, 2014, 3:41:51 PM1/20/14
to scala-i...@googlegroups.com, Simon Ochsenreither
For the record, I'm not necessarily for a macro-based solution.  I just think that not having an enum capability in a language is a false savings when it comes to mental overhead for the user.

Enums are a concept that is widely employed in programming.  It is not practical to get away from them.  Forcing users to roll their own solution on a case-by-case basis does not reduce the mental overhead for them.  Scala is amazingly powerful but its powers do not extend to a solution to the enum problem.

If macros seem like the right way to go (due to flexibility of implementation, and possibility for alternate implementations), great!  If it's going to be built into the language, great!  If there is some other way to do it (e.g. union types with a tidbit of syntactic sugar), great!

But simply failing to address the problem makes Scala harder to use for programming.  It's already so much easier than most everything else that it has some hard-to-use-ness to burn, but that doesn't mean I can't recognize that it's on fire over there.

Named and numbered collections of related things are useful.  Java has a way to deal with them with which we'd like to interoperate.  In the face of that reality, I do not presently see any better solution than macros, but I'm open to any other proposal.

  --Rex

P.S. A turing machine has a really, really small spec.

Simon Ochsenreither

unread,
Jan 20, 2014, 3:43:02 PM1/20/14
to scala-i...@googlegroups.com, Simon Ochsenreither
Would it be make sense to have something along these lines? Would it support all the required features?

...

In the light of the previous discussion, what I find appealing about this version is that is provides all the key bindings as-is (e.g. Days's methods end up being methods on Days, Days's fields end up being static fields, etc.). Sure, there is magic going on (like Days inheriting java.lang.Enum or Days getting values and valueOf), but the same kind of stuff happens with case classes, and it's not like we are unhappy about it. If that works out, I think it would be possible to come up with a mechanism that says "this annotation doesn't touch existing bindings, and only adds this, that and that", which should make things self-evident.

The verbosity part and the non-familiarity part was already mentioned, so I'd just like to bring up a semantic issue: If we don't have that "enum element notation" anymore, how do we tell which members should end up as enums and which are just "convenience" values? E. g. val Christmas = new Day(...).

With the shorter notation, users would know exactly that the "magic" is only happening for the elements with that "magic notation", and that their "valid" Scala code is not touched by the macro at all. I think that's an important benefit.

Simon Ochsenreither

unread,
Jan 20, 2014, 3:47:51 PM1/20/14
to scala-i...@googlegroups.com, Simon Ochsenreither
For the record, I'm not necessarily for a macro-based solution.  I just think that not having an enum capability in a language is a false savings when it comes to mental overhead for the user.

If macros seem like the right way to go (due to flexibility of implementation, and possibility for alternate implementations), great!  If it's going to be built into the language, great!  If there is some other way to do it (e.g. union types with a tidbit of syntactic sugar), great!

I pretty much agree with this. I'm flexible about how the solution looks like, but we shouldn't pretend that missing enums are not an issue.

Basically, I'd like to get the last two cases of bad interop with Java fixed: Enums and annotations.

The reason is that Scala usually does such a great job at inter-operating with Java, that the lack of support for enums and annotations is just highly surprising for users, and therefore creates an inconsistency within the language which I'd like to get rid of.

martin odersky

unread,
Jan 20, 2014, 3:51:34 PM1/20/14
to scala-internals, Simon Ochsenreither
The thing is, in my opinion Java's enumerations are way over-designed. It's the Edsel of enumerations; no other language spends that much specification footprint on them. I do not think we should emulate them directly, with macros or otherwise. 

Think for a moment that Javascript was our only compilation target. Javascript has no enumerations whatsoever. In light of this, what would the right design be? Not saying that JS should be our only compilation target, or that there should be no enumerations, just trying to get people to detach a bit from the Java situation.

Cheers

 - Martin

 
--
You received this message because you are subscribed to the Google Groups "scala-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-interna...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



--
Prof. Martin Odersky
LAMP/IC, EPFL
Station 14, 1015 Lausanne, Switzerland
Tel: +41 21 693 6863

Grzegorz Kossakowski

unread,
Jan 20, 2014, 3:53:20 PM1/20/14
to scala-internals, Simon Ochsenreither
On 20 January 2014 21:39, Eugene Burmako <eugene....@epfl.ch> wrote:
Indeed, the current implementation of macros has limitations, but let's temporarily think past them. What are the costs of having language features implemented as macros? Given the ideal world, would it be possible to address these costs? For one, would better IDE support would ameliorate the costs?

There's another cost: vastly bigger surface area of compiler to maintain. Without macros, the surface area is mostly: syntax, type checking (defined very abstractly), bytecode generation (in Scala: defined by implementation and Java compatibility). Everything else is implementation detail. With macros, you have to open up the whole compiler architecture (e.g. the fact that compiler is implemented using the cake) and enormous API exposing a ton of compiler's internal data structures. That's a huge price to pay.

I'm not say macros are not worth the price but it's not that everything in the garden is rosy.

Eugene Burmako

unread,
Jan 20, 2014, 4:00:58 PM1/20/14
to <scala-internals@googlegroups.com>, Simon Ochsenreither
As we discussed, reflection API should be independent from compiler's internals, and that's the direction it's already been moving in for some time (e.g. quasiquotes, macro annotations, recent patches to resetAttrs). Apart from being beneficial for macro users, this also makes the compiler healthier and more maintainable.

If there are roses even now, imagine what will become of the garden when we weed out all the unwanted plants :)


Lukas Rytz

unread,
Jan 20, 2014, 4:01:02 PM1/20/14
to scala-i...@googlegroups.com, Simon Ochsenreither
I don't agree with this reasoning. Enums are important not because of Java interop, but
because sometimes you want them in Scala.

When it comes to Java interop, I personally think that things are probably OK the way they
are now. You can use Java enums in Scala, you can use Java annotations in Scala. Sure,
you might have to write some annotation class in Java. But that's fine, you're in a mixed
project (e.g., using a Java library) anyway if you need that interop.

Rex Kerr

unread,
Jan 20, 2014, 4:04:02 PM1/20/14
to scala-i...@googlegroups.com, Simon Ochsenreither
On Mon, Jan 20, 2014 at 12:51 PM, martin odersky <martin....@epfl.ch> wrote:

The thing is, in my opinion Java's enumerations are way over-designed. It's the Edsel of enumerations; no other language spends that much specification footprint on them. I do not think we should emulate them directly, with macros or otherwise. 

We have to pay half the price already to be able to read them.  Not sure it's not worth it to just pay the rest and be done with this hole in compatibility.
 

Think for a moment that Javascript was our only compilation target. Javascript has no enumerations whatsoever. In light of this, what would the right design be?

The right design would be to have enumerations, at least of the 0-N type.  Considerations are different when you have no types.  And people are left in JS with silliness like
var DaysEnum = Object.freeze({"monday":1, "tuesday":2, "wednesday":3, ...})
 
(taken from a StackOverflow answer), which leaves to the programmer details that really ought to be the job of the compiler.  And you can get the text string trivially in JS, unlike the name of an arbitrary field in Scala.

  --Rex

Rex Kerr

unread,
Jan 20, 2014, 4:06:45 PM1/20/14
to scala-i...@googlegroups.com, Simon Ochsenreither
On Mon, Jan 20, 2014 at 1:04 PM, Rex Kerr <ich...@gmail.com> wrote:
Considerations are different when you have no types.

By "no types" I of course mean "no strong static typechecking".

One of the great benefits that enums can provide is in completeness-checking.  This is particularly appealing in a language that already supports pattern matching of more complex types.

  --Rex
 

Simon Ochsenreither

unread,
Jan 20, 2014, 4:11:48 PM1/20/14
to scala-i...@googlegroups.com, Simon Ochsenreither

The thing is, in my opinion Java's enumerations are way over-designed. It's the Edsel of enumerations; no other language spends that much specification footprint on them.

Well, most people out there agree that enums are the thing Java finally got right, even C# guys concede that point.
Of course the Java designers could have decided differently, but we need to work with the existing reality of Java's decision here. The Java spec on enums was done, and that's the way it is now. Trying to pretend that we don't have to deal with it doesn't solve any problem.
 
I do not think we should emulate them directly, with macros or otherwise. 

We are already suffering from a NIH-style enumeration class, I don't think adding another one will solve any problems. One of my goals is to end up with less half-working variations to do the same thing, not more.

Think for a moment that Javascript was our only compilation target. Javascript has no enumerations whatsoever. In light of this, what would the right design be? Not saying that JS should be our only compilation target, or that there should be no enumerations, just trying to get people to detach a bit from the Java situation.

I absolutely don't see any issue here. Translate the code, just like any other class. The only thing which needs to be done probably is to provide an implementation of java.lang.Enum for JavaScript, but that's not a big deal at all.

Hanns Holger Rutz

unread,
Jan 20, 2014, 4:51:08 PM1/20/14
to scala-i...@googlegroups.com
Which reality or problem? Java enums already work in Scala. I just
happened to add this missing Scala Swing bit:

https://github.com/Sciss/SwingPlus/blob/b117d9c0f06f5e79b1a3c007855a749b680a30d9/src/main/scala/de/sciss/swingplus/DropMode.scala

What is really the surplus value of having a Scala equivalent that boils
down to Java enums? I think Scala should emancipate itself from the idea
of having to have 1:1 mappings for each and every concept in Java. I
dream of having `null` removed from the language, for example, or `new`.

Scala needs to be an elegant and powerful language that runs primarily
(but not only) on the JVM. It needs to be able to connect to existing
Java libraries.

If there is an elegant solution for enumerated types (whether they are
encoded as Java enums or not) which doesn't complicate the language
further, fine. I am sure if there is such a solution, someone will
eventually come up with it; until then, it's good to mold design
concepts and discuss them.

Into the blue:

sealed trait Day
object Day {
case object Mon, Tue, Wed, Thu, Fri, Sat, Sun extends Day
}

(since you can write `val a, b, c = x` why not `object a, b, c extends x`?)

Other languages:

http://stackoverflow.com/questions/11856077/enums-and-clojure
http://confluence.jetbrains.com/display/Kotlin/Enum+classes

http://justanapplication.wordpress.com/2013/06/10/programming-with-rust-part-two-things-we-need-to-know-some-types/

http://stackoverflow.com/questions/6000511/better-way-to-define-an-enum-in-haskell
http://ceylon-lang.org/documentation/1.0/tour/types/

:) Best, .h.h.

Alex Cruise

unread,
Jan 20, 2014, 5:02:43 PM1/20/14
to scala-i...@googlegroups.com, Simon Ochsenreither
Just a minor datum: Out of 62 .java files in my source tree, 61 of them are enums, and the other is a package-info.java.

For comparison:
.scala: 560 files, 60 kloc
.js: 141 files, 26 kloc.

I would most likely use an enum macro annotation if it were in the standard library, and very possibly if it were easily available as something I could enable with Maven.

-0xe1a


--

Naftoli Gugenheim

unread,
Jan 20, 2014, 9:23:48 PM1/20/14
to scala-internals, Simon Ochsenreither
Martin's point was not related to javascript. What if scala had its own VM? I think what he meant is, let's give enums the best design possible, regardless of whether that happens to coincide with Java's design or not. Of course they should interoperate with Java but that shouldn't take away from better designs.




Naftoli Gugenheim

unread,
Jan 20, 2014, 9:27:18 PM1/20/14
to scala-internals



On Mon, Jan 20, 2014 at 11:35 AM, Jason Zaugg <jza...@gmail.com> wrote:
On Mon, Jan 20, 2014 at 5:10 PM, Simon Ochsenreither <simon.och...@gmail.com> wrote:
  • There are already important libraries which are basically waiting for macro annotations: Look at Slick, and their current stop-gap solution of generating source code. I really hope they don't have to deal with all the complexity of that forever, so it would be great if that approach is really just a transitional solution and not something they have to develop for the next few years.
I'd like to point out that this stop-gap solution does have *some* nice properties: it is well understood, one can control when it happens and checkin the results, and it works well with IDE completion/navigation.

In fact, I don't think it's stop-gap at all. For instance, [at least @cvogt's] plan regarding typesafe migrations (the DSL references Slick objects) is that you would keep older table definitions around (maybe a subpackage for each version), so you can for instance reference an old column in a Drop Column migration.

Therefore, I'd really prefer to give the macro styles which seem to be conceptually valid (macro methods, macro annotations, "macro typeclasses" (can't remember what it was called)) the opportunity to evolve at their own speed.
This means allowing them to mature and stabilize in parallel, instead of forcing a sequential model where we can only start working for real on "B" if "A" is done.

By making it easier to build things with them, we will get helpful feedback earlier and faster.

We've added the hooks into the compiler so that Eugene's latest work is available for early adopters in macro paradise. I think this strikes a good balance: we making research available while sending a clear signal about its status.

We're only just getting the Scala IDE to play nicely with macros of any flavour. Anything other than blackbox macros leads to a sub-par experiments in the IDE; IntelliJ can't handle it at all, and while Scala IDE can, it won't be able to in the new mode we're working on that lets you install a 2.11 IDE and use that for 2.10 projects as well.

I would really prefer that we focus on making macro author's job significantly easier before we open the gate further. Most macro implementations that I review are riddled with hygiene/ref-transparency problems. To that end, Denys is researching ways to tackle the enormous difficulty one faces in assembling trees conveniently and safely. Quasiquotes helps on the first point, but not the second.

Stepping back a little, we have to balance our investment into macros and reflection against our other goals for the language. This year, we want to focus on the backend (switching to GenBCode, Java8-style lambdas, and maybe defender methods for traits), continue to improve general quality of the library and compiler, and work towards better static analysis tools to complement the compiler. And we have to do this with a smaller team than we had last year.

-jason

--
It is loading more messages.
0 new messages