Comments (7)
After some Googling, it seems that this Enum library, Numerato, uses Macro Annotations to achieve something similar to my suggestion. It would be cool if we could have the best of both worlds :)
from enumeratum.
If you want to have a method that returns the index of any properly-implemented EnumEntry
(as in, it is inside a companion object that extends Enum
), you just need to materialise its companion object.
The following is via Ammonite
Welcome to the Ammonite Repl 0.8.1
(Scala 2.12.1 Java 1.8.0_101)
@ import $ivy.`com.beachape::enumeratum:1.5.7`, enumeratum._
import $ivy.$ , enumeratum._
@ {
// Declare 2 enums
sealed trait AgeGroup extends EnumEntry
case object AgeGroup extends Enum[AgeGroup] {
val values = findValues
case object Baby extends AgeGroup
case object Toddler extends AgeGroup
case object Teenager extends AgeGroup
case object Adult extends AgeGroup
case object Senior extends AgeGroup
}
sealed abstract class Light extends EnumEntry
case object Light extends Enum[Light] {
val values = findValues
case object Red extends Light
case object Blue extends Light
case object Green extends Light
}
}
defined trait AgeGroup
defined object AgeGroup
defined class Light
defined object Light
@ {
// indexOf for any properly-implemented Enum
def indexOf[A <: EnumEntry: Enum](entry: A): Int = {
implicitly[Enum[A]].indexOf(entry)
}
}
defined function indexOf
@ indexOf(Light.Red: Light)
res3: Int = 0
@
@ indexOf(AgeGroup.Baby: AgeGroup)
res4: Int = 0
@
@ indexOf(AgeGroup.Adult: AgeGroup)
res5: Int = 3
BTW, you'll notice that I had to add a type annotation when passing in each member; this is because otherwise, the value passed to the function will have the singleton type (e.g. AgeGroup.Adult.type
instead of AgeGroup
), which I suspect is what caused the error: not found: value
error you saw :)
As for Macro annotations, I think they're worth exploring. When Enumeratum was written, I avoided macro annotations because IDEs didn't really understand how the macros expanded w/o writing a plugin, but with Scalameta coming around the corner, that has changed (IntelliJ for example can support Scalameta macro annotations fine).
One thing I've seen quite often with the annotation-driven enum solutions is that they exchange power/flexibility in exchange for terseness. What this means is that they usually don't support the full myriad of things that Scala allows you to do, like adhock extend other traits/classes in members (e.g. the way we do stacked traits to manipulate names) or add methods and values to each member, which can come in quite handy. By the time you can support all these use-cases, you've probably got a fairly huge and complex macro.
If we go down the macro annotation route, I'd like to try our best to keep the flexibility and power that Enumeratum currently affords users. If not all, then at least cover the most important use cases :)
from enumeratum.
Interesting, I have so much more to learn :)
Good point with the name-manipulating traits, didn't think of that, hmm...maybe it could be replicated with annotation parameters? Haha
Maybe we should wait until Macros is no longer experimental and finally becomes a part of the standard library (hopefully in 2.13?)
from enumeratum.
Interesting, I have so much more to learn :)
Same here ! To be fair, in this case the error message thrown at compile time was terribly cryptic and not helpful (error: not found: value
). I've made an attempt to make it nicer with #110.
Maybe we should wait until Macros is no longer experimental and finally becomes a part of the standard library (hopefully in 2.13?)
I get the feeling that this will be a long ways in the future :). I played around with Scalameta for a while and found that it doesn't yet support things like finding the parent of a given type (for now the recommendation is if you need this kind of functionality, emit an annotation built with the old macro API), and mangles certain for-comprehensions.
So yeah I'm with you there; probably best to wait until things are more ready.
from enumeratum.
Just leaving my thoughts here for future reference:
I was just wondering what would the extent of possibilities be with Macro Annotations.
Theoretically, it would even be possible to combine Enum and ValueEnum, and maybe even allow multiple Value keys of different types to be indexed, maybe even with optional unique constraints.
Eg.
@Enum(CapitalWords)
sealed abstract class Grocery(
@EnumKey(unique = true) // should unique default to true/false?
id: Int,
@EnumKey(unique = false) // should unique default to true/false?
category: String,
exampleBool: Boolean
)
object Grocery {
case object Chicken extends Grocery(101, "Meat", true)
case object Lamb extends Grocery(102, "Meat", false)
// case object Pork extends Grocery(102, "Meat", true) <-- will fail to compile because the id 102 must be unique
case object Coke extends Grocery(201, "Beverage", false)
}
would expand to:
sealed abstract class Grocery(id: Int, category: String, exampleBool: Boolean) extends EnumEntry with CapitalWords
object Grocery extends Enum[Grocery] {
case object Chicken extends Grocery(101, "Meat")
case object Lamb extends Grocery(102, "Meat")
case object Coke extends Grocery(201, "Beverage")
val values: immutable.IndexedSeq[Grocery] = IndexedSeq(Chicken, Lamb, Coke)
private val idToEntriesMap: immutable.Map[Int, Grocery] =
Map(
Chicken.id -> Chicken,
Lamb.id -> Lamb,
Coke.id -> Coke
)
private val categoryToEntriesMap: immutable.Map[String, Set[Grocery]] = ??? // some MultiMap implementation (Scala's MultiMap seems lacking...maybe Google Guava's HashMultimap?)
def withId(id: Int): Grocery = idToEntriesMap(id)
def withCategory(category: String): Set[Grocery] = categoryToEntriesMap(category)
}
It may even be possible to make the syntax even more concise (see Numerato)
from enumeratum.
Theoretically, pretty much anything is possible with macros ;) Just take a look at scala-async or quill. Practically speaking, my experience is that the size and complexity of the macro grow non-linearly with every feature (language level) you want to support because essentially you're on your own building an AST transformer. The difficulty balloons even more when concise syntax is also a goal, which is why most of those brevity-focused libs aren't as powerful as Enumeratum.
Having said that, I think your design looks nice and it's worth considering how Enumeratum should evolve in the future. I'll close this issue for now and open another one for the purpose of discussing future designs.
from enumeratum.
Thanks. I'll also open a new issue for the EnumSet/EnumMap implementation.
from enumeratum.
Related Issues (20)
- EnumEntry initialization-order problem. HOT 1
- Solution for generic typeclass derivation for Enums! HOT 2
- Any suggested way to forbid calls to `toString` on `EnumEntry`ies? HOT 2
- Cannot initialize enum value with static final Java field HOT 3
- 1.7.1 release is not found in registry HOT 2
- Enums with hierarchical structure HOT 2
- Avoid the use of `toString` for `enumEntry`? HOT 4
- [Scala 2] Compile-time stackoverflow with lots of enum values HOT 3
- Version 1.7.2 is not binary compatible with previous versions HOT 2
- Conflict with Scala 3 enums HOT 5
- Breaking compatibility should trigger a major version update HOT 2
- .
- enumeratum-json4s not available for Scala3? HOT 5
- Scala3: findValues fails to compile in nested sealed trait hierarchy HOT 1
- Scala 3: findValues fails to find entries extending types with type parameters HOT 1
- How to upgrade enumeratum-doobie to target v1.0.0-RC4 HOT 3
- Un-sealed abstract class in hierarchy gets ignored on Scala 3.x HOT 1
- Support play-json 3.0.x
- Members of enums nested in a class are not discovered in scala 3 HOT 1
- Derived `CirceEnum` codecs fail roundtrip on `case class` values HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from enumeratum.