Enumeratum

Enumeratum is a type-safe and powerful enumeration implementation for Scala that offers exhaustive pattern match warnings, integrations with popular Scala libraries, and idiomatic usage that won't break your IDE. It aims to be similar enough to Scala's built in Enumeration to be easy-to-use and understand while offering more flexibility, type-safety (see this blog post describing erasure on Scala's Enumeration), and richer enum values without having to maintain your own collection of values.

The name is taken from the toString method of the particular EnumEntry. This behavior can be changed in two ways.

Manual override of name

The first way to change the name behaviour is to manually override the def entryName: String method.

importenumeratum._sealedabstractclassState(overridevalentryName:String) extendsEnumEntryobjectStateextendsEnum[State] {
valvalues= findValues
caseobjectAlabamaextendsState("AL")
caseobjectAlaskaextendsState("AK")
// and so on and so forth.
}
importState._State.withName("AL")

Mixins to override the name

The second way to override the name behaviour is to mixin the stackable traits provided for common string conversions, Snakecase, UpperSnakecase, CapitalSnakecase, Hyphencase, UpperHyphencase, CapitalHyphencase, Dotcase, UpperDotcase, CapitalDotcase, Words, UpperWords, CapitalWords, Camelcase, LowerCamelcase, Uppercase, Lowercase, and Uncapitalised.

ValueEnum

Asides from enumerations that resolve members from Stringnames, Enumeratum also supports ValueEnums, enums that resolve members from simple values like Int, Long, Short, Char, Byte, and String (without support for runtime transformations).

These enums are not modelled after Enumeration from standard lib, and therefore have the added ability to make sure, at compile-time, that multiple members do not share the same value.

SBT

Note that as of version 1.4.0, enumeratum-play for Scala 2.11 is compatible with Play 2.5+ while 2.10 is compatible with Play 2.4.x. Versions prior to 1.4.0 are compatible with 2.4.x.

Usage

PlayEnum

The included PlayEnum trait is probably going to be the most interesting as it includes a bunch of built-in implicits like Json formats, Path bindables, Query string bindables, and Form field support.

For example:

packageenumsimportenumeratum._sealedtraitGreetingextendsEnumEntryobjectGreetingextendsPlayEnum[Greeting] {
valvalues= findValues
caseobjectHelloextendsGreetingcaseobjectGoodByeextendsGreetingcaseobjectHiextendsGreetingcaseobjectByeextendsGreeting
}
/* Then make sure to import your PlayEnums into your routes in your Build.scala or build.sbt so that you can use them in your routes file. `routesImport += "enums._"`*/// You can also use the String Interpolating Routing DSL:importplay.api.routing.sird._importplay.api.routing._importplay.api.mvc._Router.from {
caseGET(p"/hello/${Greeting.fromPath(greeting)}") =>Action {
Results.Ok(s"$greeting")
}
}

PlayValueEnums

There are IntPlayEnum, LongPlayEnum, and ShortPlayEnum traits for use with IntEnumEntry, LongEnumEntry, and ShortEnumEntry respectively that provide Play-specific implicits as with normal PlayEnum. For example:

ReactiveMongoBsonValueEnum

There are IntReactiveMongoBsonValueEnum, LongReactiveMongoBsonValueEnum, and ShortReactiveMongoBsonValueEnum traits for use with IntEnumEntry, LongEnumEntry, and ShortEnumEntry respectively. For example:

ScalaCheck

SBT

Usage

Enum

Given the enum declared in the quick-start section, you can get an Arbitrary[Greeting] (to generate instances of Greeting) and a Cogen[Greeting] (to generate instances of Greeting => (A: Arbitrary)) by importing generators in the scope of your tests:

importenumeratum.scalacheck._

ValueEnum

Similarly, you can get Arbitrary and Cogen instances for every ValueEnum subtype by importing generators in the scope of your tests:

Slick integration

Column Mappings

In order to use your enumeratum Enums in Slick tables as columns, you will need to construct instances of MappedColumnType and make them available where you define and query your slick tables. In order to more easily construct these instances, the enumeratum-slick integration provides a trait enumeratum.SlickEnumSupport. This trait provides a method mappedColumnTypeForEnum (and variants) for constructing a mapped column type for your enum. For example if you want to use Enum[Greeting] in your slick table, mix in SlickEnumSupport where you define your table.

Common Mappers

An alternate approach which is useful when mappers need to be shared across repositories (perhaps for something common like a "Status" enum) is to define your mappers in a module on their own, then make use of them in your repositories:

Querying by enum column types

Note that because your enum values are singleton objects, you may get errors when you try to use them in Slick queries like the following:

.filter(_.trafficLight ===TrafficLight.Red)

This is because TrafficLight.Red in the above example is inferred to be of its unique type (TrafficLight.Red) rather than TrafficLight, thus causing a failure to find your mapping. In order to fix this, simply assist the compiler by ascribing the type to be TrafficLight:

.filter(_.trafficLight === (TrafficLight.Red:TrafficLight))

A way around this if you find the type expansion offensive is to define val accessors for your enum entries that are typed as the parent type. You can do this inside your Enums companion object or more locally:

Usage

This enumeratum module is mostly useful for generic derivation - providing instances for Eq, Show and Hash. So if you have structures (for example case classes) which contain enum values, you get the instances for the enum itself "for free". But it can be useful for standalone usage as, providing type-safe comparison and hashing.

ValueEnum

There are two implementations for ValueEnum:

CatsValueEnum provides the same functionality as CatsEnum (except Hash)

CatsOrderValueEnum provides the same functionality as CatsValueEnum plus an instance of cats.Order (due to Scala 2 trait limitations, it's an abstract class, check out CatsCustomOrderValueEnum if you need a trait)

Inheritance-free usage

If you need instances, but hesitate to mix in the traits demonstrated above, you can get them using the provided methods in enumeratum.Cats and enumeratum.values.Cats - the second also provides more flexibility than the (opinionated) mix-in trait as it allows to pass a custom type class instance for the value type (methods names are prefixed with value).

Discussion

Other than the methods that throw NoSuchElementExceptions, performance is in the 10ns range (taking into account JMH overhead of roughly 2-3ns), which is acceptable for almost all use-cases. PRs that promise to increase performance are expected to be demonstrably faster.

Also, Enumeratum's withName is faster than the standard library's Enumeration, by around 4x in the case where an entry exists with the given name. My guess is this is because Enumeratum doesn't use any synchronized calls or volatile annotations. It is also faster in the case where there is no corresponding name, but not by a significant amount, perhaps because the high cost of throwing an exception masks any benefits.

Publishing

Projects are published independently of each other.

JVM + ScalaJS projects should have an aggregate project to make it easy to publish them, e.g. for enumeratum-circe:

$ sbt "project circe-aggregate" +clean +publish-signed

Should publish all needed artefacts. Note that sbt circe-aggregate/publish-signed will not work (ScalaJS gets skipped).