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.
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 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.
Provide enumerations without the overhead of one class per value.
Enumerations in Java are quite enormous, similar in complexity to, say, traits in Scala. Is the convenience really worth it?
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.
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 oneclass 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
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
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.
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?
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.
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.").
Unsafe numbering, namespace pollution, ints-only
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.
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 ...
I think we can make Enumeration a trait macro, given we empower trait macros to read contents of host classes
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.
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.
object CompassPoint {val North = new CompassPointval South = new CompassPointval East = new CompassPointval 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!
You can't easily add functionality to Java enums.
object Flag extends Enumeration {
Forward
Occupied
Updated
ArrayBacked
Extra
}
trait Flag extends Flag.Enumerated {
val value = 1 << ordinal
}
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.
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.
and allows (at compile-time) but breaks on repeated values (numeric constants allow repeats and do not break):
(Although it may need to be extends...)
Oops, the subconscious grammar pedant overrode the intention. I meant to type extends.
And I don't know anymore whether generating java enum is the real goal.
For the syntactic thing with case objects, which does annoy, I wonder if we could gift ourselvescase object Monday, Tuesday, Wednesday, Thursday, Friday extend Weekday
--
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.
case Tuesday(_) =>(dc: DayConstructors) match {case Monday(_) =>
}
// warning on missing cases
Just wow! That's enum I want!
--
--
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.
Very exciting!Are there rules as to what other statements you're allowed to write inside an @enum?
How do a sign up?
Or, when will this make it in into Scala-land?
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
- 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.
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.
- 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.
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...
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.
--
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.
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!
--
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.
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?
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?
var DaysEnum = Object.freeze({"monday":1, "tuesday":2, "wednesday":3, ...})
Considerations are different when you have no types.
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.
--
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
--