Skip to content

Enumz

One enum type class to rule them all


What Enumz does

In Scala, you might meet many different implementations of enums:

  • build-in scala.Enumeration,
  • sum-type based sealed hierarchies,
  • enumeratum as the previous one on steroids,
  • Java's enum type which use static methods and has no companion object.

You are in control of what implementation you pick, but you have no control over what other people use. So if you had to use APIs using many different implementations how would you handle common code?

With a type class.

Usage

Add to your sbt (2.12, 2.13 and 3.3+ supported):

libraryDependencies += "io.scalaland" %% "enumz" % "1.2.0"

or, if you use Scala.js

libraryDependencies += "io.scalaland" %%% "enumz" % "1.2.0"

From now on you can define enums whatever you want and use one common interface for all of them.

Example

public enum TestJavaEnum {
    A, B, C
}
object TestEnumeration extends Enumeration {
  type TestEnumeration = Value
  val A, B, C = Value
}
sealed trait TestSumType extends Product with Serializable
object TestSumType {
  case object A extends TestSumType
  case object B extends TestSumType
  case object C extends TestSumType
}
import enumeratum.{Enum => EnumeratumEnum, _}

sealed trait TestEnumeratum extends EnumEntry
object TestEnumeratum extends EnumeratumEnum[TestEnumeratum] {
  val values = findValues
  case object A extends TestEnumeratum
  case object B extends TestEnumeratum
  case object C extends TestEnumeratum
}
import io.scalaland.enumz.Enum

Enum[TestJavaEnum].values
Enum[TestEnumeration.TestEnumeration].values
Enum[TestSumType].values
Enum[TestEnumeratum].values

You can also test it with Scala CLI like:

Example

//> using def o.scalaland::enumz::1.2.0
import io.scalaland.enumz.Enum

sealed trait TestSumType extends Product with Serializable
object TestSumType {
  case object A extends TestSumType
  case object B extends TestSumType
  case object C extends TestSumType
}

Enum[TestSumType].values

Available methods

Example

 Enum[TestSumType].values // Vector(TestSumType.A, TestSumType.B, TestSumType.C)
 Enum[TestSumType].indices // Map(TestSumType.A -> 0, TestSumType.B -> 1, TestSumType.C -> 2)

 Enum[TestSumType].getName(TestSumType.A) // "A"
 Enum[TestSumType].getIndex(TestSumType.A) // 0

 Enum[TestSumType].withIndexOption(0) // Some(TestSumType.A)
 Enum[TestSumType].withIndexOption(-1) // None

 Enum[TestSumType].withIndex(0) // TestSumType.A
 Enum[TestSumType].withIndex(-1) // throws!

 Enum[TestSumType].withNameOption("A") // Some(TestSumType.A)
 Enum[TestSumType].withNameOption("") // None

 Enum[TestSumType].withName("A") // TestSumType.A
 Enum[TestSumType].withName("") // throws!

 Enum[TestSumType].withNameInsensitiveOption("a") // Some(TestSumType.A)
 Enum[TestSumType].withNameInsensitiveOption("") // None

 Enum[TestSumType].withNameInsensitive("a") // TestSumType.A
 Enum[TestSumType].withNameInsensitive("") // throws!

 Enum[TestSumType].`A` // TestSumType.A

Chimney integration

Add:

libraryDependencies += "io.scalaland" %% "enumz-chimney" % "1.2.0"

and then import:

import io.scalaland.enumz.chimney._

to be able to transform between all supported types with PartialTransformers

Example

Enum[TestEnumeration.TestEnumeration].values
  .transformIntoPartial[Vector[TestEnumeratum]]
  .asOption == Some(Enum[TestEnumeratum].values)

Enum[TestEnumeratum].values
  .transformIntoPartial[Vector[TestSumType]]
  .asOption == Some(Enum[TestSumType].values)

Enum[TestSumType].values
  .transformIntoPartial[Vector[TestEnumeration.TestEnumeration]]
  .asOption == Some(Enum[TestEnumeration.TestEnumeration].values)

Provide your own implicit EnumNamesComparison to control how enum values' names would be compared in runtime:

// the default
import EnumNamesComparison.Implicits.strictEquality
// case-insensitice
import EnumNamesComparison.Implicits.caseInsensitiveEquality

implicit val yourOwnComparator: EnumNamesComparison =
  (fromName: String, toName: String) => ...

Tip

Since Chimney is able to convert between sealed traits/scala 3 enums/Java enums without failing, use this module only if you want to move the transformation into runtime, e.g. to support scala.Enumaration.