Scala programmers have a few options when defining enumerations:
When researching the best practices around enumerations in Scala, I stumbled upon the Google post entitled Enumerations must DIE and also this blog which highlights a potential problem using the Scala Enumeration
class. Both these references have cast a negative shadow over the Scala Enumeration
class.
Option 2 seems like a lot of work and with regards to Option 3, I have not used the Scalaz library as of yet so I would interested to know the experience others have had with using Scalaz
Enum
. The final option is to inter-op with Java which I try to avoid since I like to take a purist approach in my Scala programming.
The point of this post is to leverage the community experience in order to detail the context(s) when one option would be preferred over another and also in which context(s) would using a particular option be wrong or likely to cause serious issues, so that an informed decision can be made in choosing one option over another. I am not looking for opinions but rather concrete use context(s) when one option is better than the other(s); opinions are likely to get this post closed down so please avoid that.
Scalaz Enum
Enum
succ
and pred
functionsorder
function from the Order
type class.Example
import scalaz.Ordering.{EQ, GT, LT}
import scalaz.{Enum, Ordering, Show}
sealed abstract class Coloring(val toInt: Int, val name: String)
object Coloring extends ColoringInstances {
case object RED extends Coloring(1, "RED")
case object BLUE extends Coloring(2, "BLUE")
case object GREEN extends Coloring(3, "GREEN")
}
sealed abstract class ColoringInstances {
import Coloring._
implicit val coloringInstance: Enum[Coloring] with Show[Coloring] = new Enum[Coloring] with Show[Coloring] {
def order(a1: Coloring, a2: Coloring): Ordering = (a1, a2) match {
case (RED, RED) => EQ
case (RED, BLUE | GREEN) => LT
case (BLUE, BLUE) => EQ
case (BLUE, GREEN) => LT
case (BLUE, RED) => GT
case (GREEN, RED) => GT
case (GREEN, BLUE) => GT
case (GREEN, GREEN) => EQ
}
def append(c1: Coloring, c2: => Coloring): Coloring = c1 match {
case Coloring.RED => c2
case o => o
}
override def shows(c: Coloring) = c.name
def zero: Coloring = Coloring.RED
def succ(c: Coloring) = c match {
case Coloring.RED => Coloring.BLUE
case Coloring.BLUE => Coloring.GREEN
case Coloring.GREEN => Coloring.RED
}
def pred(c: Coloring) = c match {
case Coloring.GREEN => Coloring.BLUE
case Coloring.BLUE => Coloring.RED
case Coloring.RED => Coloring.GREEN
}
override def max = Some(GREEN)
override def min = Some(RED)
}
}
Example Output:
val f = Enum[Coloring]
println(f.fromToL(Coloring.RED, Coloring.GREEN))
res1 : List(RED, BLUE, GREEN)
I have used both of the first two options in the past depending on the circumstances. I can't speak for the other options but I would be reluctant to use Java Enums. Generally I will always prefer a Scala solution over a Java solution where one is available. I would also be reluctant to introduce a library just for Enumerations. It seems a bit heavy to introduce a large library to accomplish such a small task, especially when there are built in ways to accomplish that task. It might be different though if the library was offering other features that I wanted which were not built in.
Part of it depends on what you need the enumeration to accomplish. If you need it just to create a set of discrete values, then I would lean towards Option 2. It really isn't much work at all. You can make it more complex if your needs require it, but the most basic scenario is:
trait MyEnum
case object MyValue1 extends MyEnum
case object MyValue2 extends MyEnum
If on the other hand you need something that actually provides you with an "ordered" set of discrete values that you can iterate over, obtain numeric values for etc, then I might lean more towards the Scala Enumeration.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With