Enumeratum: Sealed Trait Enums for Scala
If you’ve been working with Scala for a while, you might have come across a few “problems” with the built in Enumeration
that’s provided out-of-the-box. This is especially true if you have colleagues who come from a Java background and yearn for the Java-style Enum
that gave them lots of power and flexibility.
A quick search on the internet for “Scala enumeration alternative” will yield a lot of results (perhaps on StackOverflow) where people have cooked up their own implementation of enumerations, usually built on sealed traits
. Personally, I found most of them to be either too inconvenient to use, too over-powered, or too complicated, and I really didn’t want to have to copy-paste enum-related code into all my projects.
Thus Enumeratum was born.
Enumeratum aims to be simple to use, idiomatic, small (LoC), yet flexible enough to allow Scala devs to make power enums if they so wish. It is also Mavenised for easy import into any project.
To use it, simply add it as a dependency
1 2 3 4 5 |
|
Then
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
|
You get nice things like exhaustive match warnings at compile-time, enums with methods, no more Enum-value type erasure, and other nice stuff.
How it works
Some of the solutions for custom enums out there are based on macros that reflect at compile time using knownDirectSubclasses
to find enum values, but as of writing, there is a 2 year old bug for that method.
As a result, Enumeratum uses another method of finding enum values: looking in an enclosed object to find the enum values. The macro behind findValues
does this for you so that you don’t have to maintain your own collection of enum values, which is both error-prone and tedious.
Play
If you want to use Enumeratum in a Play app, you may as well add enumeratum-play
as a dependency instead so that you can use the PlayEnum[A]
trait (instead of Enum[A]
), which will give you nice things like QueryStringBinders, PathBinders, form mappers, and Json Reads/Writes/Formats. To make use of this integration, just extend from PlayEnum
instead of Enum
in the above example.
This means less boilerplate in your project, which is A Good Thing, right?
Limitations
There are a few limitations with Enumeratum:
- ~~Ordinality is not taken care of. From what I’ve seen, this is one of the least-used functions of Enums in general. That said, nothing is stoping you from defining an
Ordering
in your companion object for your sealed trait.~~ - Because the Enum values are case objects, they will be inferred to have their own specific type, which may cause problems with compilation for typeclasses that are not contravariant. In that case, simply help the compiler by adding a type (e.g.
val myPhone: Phone = Iphone
) - ~~The method
withName
relies on thetoString
method of the Enum values for lookup. Make sure to override this if you have specific requirements.~~
Update 2016/04/22 Crossed out a bunch of limitations that no longer apply.
Enjoy
I hope Enumeratum can help you out of your Enumeration
woes. Have a look, play around, and send a PR or two !