It’s been a while since the last major release of Enumeratum, and in 1.4.0, minor changes include Play 2.5 support, integration library version bumps, and small internal refactorings. More excitingly though, the latest version adds support for a new kind of enumeration,
ValueEnum, as well as an integration with the Circe JSON library.
Points of interest:
- Unlike other value enum implementations, Enumeration’s value enums perform uniqueness checks at compile time to make sure you have unique values across your enum members.
- Circe integration allows you to send and receive JSON data between your front end and your server using the same code
The 1.4.0 release page on Github has a more detailed list of changes, but we’ll specifically go through:
What is a
ValueEnum? It’s an enum that represents a primitive value (e.g.
Short) instead of a
String. I may have just made up the term, but it doesn’t matter as long as you know what I mean.
1 2 3 4 5 6 7 8
This may sound mundane, since you can already build something like this yourself with the standard library’s
Enumeration (or previous versions of Enumeratum ), but sometimes the most straightforward solutions are suboptimal.
The trouble with
The standard lib’s
Enumeration comes with the notion of a customisable
id: Int on each member, which is a great starting point for implementing numbers-based enumerations.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
This funny behaviour is caused by the fact that
Fourth) are not checked for unique ids at compile time, and are instantiated when their outer
Enumeration object is lazily instantiated. When a
Value is instantiated, its
id is stuffed into a
HashMap[Int, Value] after an assertion check that the id does not already exist in the map.
What has happend in the above example is the enumeration code compiles, but when we call
object Things gets instantiated, and throws an assertion error when
val Fourth is being instantiated with an id of 3, which has already been assigned to
Third and thus is already in the aforementioned
HashMap. This prevents the singleton
Things from getting instantiated, and the next time you try to use it, Scala will throw a
One way to work around this is to write tests for every such
Enumeration to make sure that no one working in the code base has fat-fingered any ids. I’m a big proponent of writing tests, but tests are also code and come with a maintenance and cognitive cost, so I would prefer not having to write tests to make sure my simple value enums can be safely initialised.
This kind of problem is not limited to
Enumeration: careless implementation of something similar may result in arguably freakier outcomes such as silent failures (2 members with the same value but only one of the members can be retrieved by value).
In version 1.4.0 of Enumeratum, we’ve introduced 3 pairs of traits:
ShortEnumEntry. As their names suggest, these are value enum traits that allow you to create enums that are backed by
Short respectively. Each pair extends
ValueEnumEntry. Note that this class hierarchy is a bit extensive for now, and it may be more streamlined in the future.
This is an example of how you would create an
Long based value enum with Play integration (JSON readers and writers, Query string binders, Path binders, Form formatters, etc):
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
findValues method of
ValueEnums works similarly to the
findValues method of Enumeratum’s older
Enum, except the macro will ensure that there is a literal
value member or constructor for each enum entry and fails the compilation if more than one member shares the same value.
As the above example demonstrates, there are Play (and standalone Play-JSON) integrations available for this new kind of enum, as well as for UPickle, and Circe.
~~Note that this new feature is not yet available in Scala 2.10 and in the REPL due to Macro expansion differences~~ (update: now works in the REPL and is available for 2.10.x!).
Enumeratum 1.4.0 also adds support for serialising/deserialising to JSON using Circe, an up-and-coming performant and feature-filled JSON library published for both JVM and ScalaJS.
This is how you would use Circe with Enumeratum’s
Enum (integrations for
ValueEnum also exist)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Hopefully, Enumeratum’s new
ValueEnum implementations will make development easier and safer for engineers out there who need to use value enumerations. Since uniqueness is checked at compile-time, you can save yourself the trouble of writing a bunch of pedantic tests. Circe is a promising JSON library that was really easy to integrate with and I look forward to taking advantage of the fact that it works on both server side and on the front end.
As always, if you have any problems, questions, suggestions, or better yet, PRs, please do not hesitate to get in touch on Github.