SkillAgentSearch skills...

Enumeratum

A type-safe, reflection-free, powerful enumeration implementation for Scala with exhaustive pattern match warnings and helpful integrations.

Install / Use

/learn @lloydmeta/Enumeratum
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Enumeratum Continuous integration codecov Maven Central Scala.js Join the chat at https://gitter.im/lloydmeta/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.

Enumeratum has the following niceties:

  • Zero dependencies
  • Performant: Faster thanEnumeration in the standard library (see benchmarks)
  • Allows your Enum members to be full-fledged normal objects with methods, values, inheritance, etc.
  • ValueEnums that map to various primitive values and have compile-time uniqueness constraints.
  • Idiomatic: you're very clearly still writing Scala, and no funny colours in your IDE means less cognitive overhead for your team
  • Simplicity; most of the complexity in this lib is in its macro, and the macro is fairly simple conceptually
  • No usage of reflection at runtime. This may also help with performance but it means Enumeratum is compatible with ScalaJS and other environments where reflection is a best effort (such as Android)
  • No usage of synchronized, which may help with performance and deadlocks prevention
  • All magic happens at compile-time so you know right away when things go awry
  • Comprehensive automated testing to make sure everything is in tip-top shape

Enumeratum is published for Scala 2.12.x, 2.13.x, 3.x as well as ScalaJS and ScalaNative.

Note that there are a couple of limitations for 3.x:

  • All "immediate" parent types of enum entries need to be sealed (reasoning here)
  • The -Yretain-trees Scalac option must be set when using ValueEnums

Integrations are available for:

Table of Contents

  1. Quick start
  2. More examples
  3. ScalaJS
  4. Play integration
  5. Play JSON integration
  6. Circe integration
  7. ReactiveMongo BSON integration
  8. Argonaut integration
  9. Json4s integration
  10. Slick integration
  11. ScalaCheck
  12. Quill integration
  13. Cats integration
  14. Doobie integration
  15. Anorm integration
  16. Benchmarking
  17. Publishing
  18. Contributing

Quick start

SBT

Maven Central

In build.sbt, set the Enumeratum version in a variable (for the latest version, set val enumeratumVersion = the version you see in the Maven badge above).

libraryDependencies ++= Seq(
    "com.beachape" %% "enumeratum" % enumeratumVersion
)

Enumeratum has different integrations that can be added to your build à la carte. For more info, see the respective sections in the Table of Contents

Usage

Using Enumeratum is simple. Just declare your own sealed trait or class A that extends EnumEntry and implement it as case objects inside an object that extends from Enum[A] as shown below.


import enumeratum._

sealed trait Greeting extends EnumEntry

object Greeting extends Enum[Greeting] {

  /*
   `findValues` is a protected method that invokes a macro to find all `Greeting` object declarations inside an `Enum`

   You use it to implement the `val values` member
  */
  val values = findValues

  case object Hello   extends Greeting
  case object GoodBye extends Greeting
  case object Hi      extends Greeting
  case object Bye     extends Greeting

}

// Object Greeting has a `withName(name: String)` method
Greeting.withName("Hello")
// => res0: Greeting = Hello

Greeting.withName("Haro")
// => java.lang.NoSuchElementException: Haro is not a member of Enum (Hello, GoodBye, Hi, Bye)

// A safer alternative would be to use `withNameOption(name: String)` method which returns an Option[Greeting]
Greeting.withNameOption("Hello")
// => res1: Option[Greeting] = Some(Hello)

Greeting.withNameOption("Haro")
// => res2: Option[Greeting] = None

// It is also possible to use strings case insensitively
Greeting.withNameInsensitive("HeLLo")
// => res3: Greeting = Hello

Greeting.withNameInsensitiveOption("HeLLo")
// => res4: Option[Greeting] = Some(Hello)

// Uppercase-only strings may also be used
Greeting.withNameUppercaseOnly("HELLO")
// => res5: Greeting = Hello

Greeting.withNameUppercaseOnlyOption("HeLLo")
// => res6: Option[Greeting] = None

// Similarly, lowercase-only strings may also be used
Greeting.withNameLowercaseOnly("hello")
// => res7: Greeting = Hello

Greeting.withNameLowercaseOnlyOption("hello")
// => res8: Option[Greeting] = Some(Hello)

Note that by default, findValues will return a Seq with the enum members listed in written-order (relevant if you want to use the indexOf method).

Enum members found in nested objects will be included by findValues as well, and will appear in the order they are written in the companion object, top to bottom. Note that enum members declared in traits or classes will not be discovered by findValues. For example:

sealed trait Nesting extends EnumEntry
object Nesting extends Enum[Nesting] {
  val values = findValues

  case object Hello extends Nesting
  object others {
    case object GoodBye extends Nesting
  }
  case object Hi extends Nesting
  class InnerClass {
    case object NotFound extends Nesting
  }
}

Nesting.values
// => res0: scala.collection.immutable.IndexedSeq[Nesting] = Vector(Hello, GoodBye, Hi)

For an interactive demo, checkout this Scastie snippet.

More examples

Enum

Continuing from the Greeting enum declared in the quick-start section:

import Greeting._

def tryMatching(v: Greeting): Unit = v match {
  case Hello   => println("Hello")
  case GoodBye => println("GoodBye")
  case Hi      => println("Hi")
}

/**
Pattern match warning ...

<console>:24: warning: match may not be exhaustive.
It would fail on the following input: Bye
       def tryMatching(v: Greeting): Unit = v match {

*/

Greeting.indexOf(Bye)
// => res2: Int = 3

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.


import enumeratum._

sealed abstract class State(override val entryName: String) extends EnumEntry

object State extends Enum[State] {

   val values = findValues

   case object Alabama extends State("AL")
   case object Alaska  extends State("AK")
   // and so on and so forth.
}

import State._

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.


import enumeratum._
import enumeratum.EnumEntry._

sealed trait Greeting extends EnumEntry with Snakecase

object Greeting extends Enum[Greeting] {

  val values = findValues

  case object Hello        extends Greeting
  case object GoodBye      extends Greeting
  case object ShoutGoodBye extends Greeting with Uppercase

}

Greeting.withName("hello")
Greeting.withName("good_bye")
Greeting.withName("SHOUT_GOOD_BYE")

ValueEnum

Asides from enumerations that resolve members from String names, Enumeratum also supports ValueEnums, enums that resolve members from simple values like Int, `Long

Related Skills

View on GitHub
GitHub Stars1.2k
CategoryDevelopment
Updated1d ago
Forks152

Languages

Scala

Security Score

100/100

Audited on Mar 28, 2026

No findings