Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enumeration concept in Scala - Which option to take?

Tags:

scala

Scala programmers have a few options when defining enumerations:

  1. Use Scala Enumeration
  2. Mimic enumerations using Scala sealed case objects.
  3. Use Scalaz Enum
  4. Use Java Enumeration

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.

like image 640
M.K. Avatar asked Feb 18 '15 16:02

M.K.


2 Answers

Scalaz Enum

  • Enumeration concept in Scalaz is modelled on the Haskell Enum
  • Provides useful operations on sequentially ordered types
  • Develop rich enumerations through sealed case classes
  • Iterate over those sealed case classes in a type-safe manner
  • More analysis is required on the part of implementer to define the notion of order for the type that is sought to be enumerated.
  • Required to define succ and pred functions
  • Required to override the order 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)
like image 91
M.K. Avatar answered Oct 14 '22 01:10

M.K.


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.

like image 35
Wade Avatar answered Oct 14 '22 02:10

Wade