[ACCEPTED]-How do I create an enum in scala that has an extra field-enums

Accepted answer
Score: 15

overthink is right, but there's a less verbose 1 way of declaring the case objects:

sealed abstract class FlatFileHeaderMapping(val fieldSize: Int)
case object HEADER_EL extends FlatFileHeaderMapping(1)
case object HEADER_RESERVED1 extends FlatFileHeaderMapping(5)
case object HEADER_RESERVED2 extends FlatFileHeaderMapping(2)
case object HEADER_MESSAGE_TYPE extends FlatFileHeaderMapping(4)
Score: 5

You could try using case objects:

sealed trait FlatFileHeaderMapping { val fieldSize: Int }                                                                                                                                                                          
case object HEADER_EL extends FlatFileHeaderMapping { val fieldSize = 1 }                                                                                                  
case object HEADER_RESERVED1 extends FlatFileHeaderMapping { val fieldSize = 5 }                                                                                           
case object HEADER_RESERVED2 extends FlatFileHeaderMapping { val fieldSize = 2 }                                                                                           
case object HEADER_MESSAGE_TYPE extends FlatFileHeaderMapping { val fieldSize = 4 } 

You can then use the 7 enum like so:

object Test {                                                                                                                                                              
  def foo(x: FlatFileHeaderMapping) {                                                                                                                                      
    val result =                                                                                                                                                           
      x match {
        case HEADER_EL => "it's a HEADER_EL!"                                                                                                                              
        case other => "its field size is: " + other.fieldSize                                                                                                             

  def main(args: Array[String]) {                                                                                                                                          

The main nicety you get here 6 is compile-time checking that all enum values 5 are handled. i.e in the x match { ... } code above you'd 4 get a compile error if you didn't have the 3 'case other => ...` clause in there.

I'm 2 pretty much just restating this answer, which lists 1 pros and cons of this approach.

Score: 1
object Direction extends Enumeration {
  val North = Value("North")
  val East = Value("East")
  val South = Value("South")
  val West = Value("West")

scala> import Direction._
scala> values foreach println
scala> val map = HashMap(North -> 1, South -> 2)


Score: 0

This is answered in Enumeration with constructor and lookup table

A simpler solution 1 exist for integer value:

object FlatFileHeaderMapping extends Enumeration  {
   type FlatFileHeaderMapping = Value 
   val HEADER_EL = Value(1, "HEADER_EL")
Score: 0

Reproducing the contents of the accepted 3 answer, as it's hidden behind a broken Tumblr 2 link (that I accessed via Archive.org), which 1 in turn points to this page.

trait Enum { //DIY enum type
  import java.util.concurrent.atomic.AtomicReference //Concurrency paranoia

  type EnumVal <: Value //This is a type that needs to be found in the implementing class

  private val _values = new AtomicReference(Vector[EnumVal]()) //Stores our enum values

  //Adds an EnumVal to our storage, uses CCAS to make sure it's thread safe, returns the ordinal
  private final def addEnumVal(newVal: EnumVal): Int = { import _values.{get, compareAndSet => CAS}
    val oldVec = get
    val newVec = oldVec :+ newVal
    if((get eq oldVec) && CAS(oldVec, newVec)) newVec.indexWhere(_ eq newVal) else addEnumVal(newVal)

  def values: Vector[EnumVal] = _values.get //Here you can get all the enums that exist for this type

  //This is the trait that we need to extend our EnumVal type with, it does the book-keeping for us
  protected trait Value { self: EnumVal => //Enforce that no one mixes in Value in a non-EnumVal type
    final val ordinal = addEnumVal(this) //Adds the EnumVal and returns the ordinal

    def name: String //All enum values should have a name

    override def toString = name //And that name is used for the toString operation
    override def equals(other: Any) = this eq other.asInstanceOf[AnyRef]
    override def hashCode = 31 * (this.getClass.## + name.## + ordinal)

//And here's how to use it, if you want compiler exhaustiveness checking
object Foos extends Enum {
  sealed trait EnumVal extends Value /*{ you can define your own methods etc here }*/

  val F = new EnumVal { val name = "F" }
  val X = new EnumVal { val name = "X" }

scala> Foos.values.find(_.name == "F")
res3: Option[Foos.EnumVal] = Some(F)

scala> Foos.X.ordinal
res4: Int = 1

scala> def doSmth(foo: Foos.EnumVal) = foo match {
  case Foos.X => println("pigdog")

<console>:10: warning: match is not exhaustive!
missing combination        $anon$1
missing combination        $anon$2

scala> def doSmth(foo: Foos.EnumVal) = foo match {
         case Foos.X => println("pigdog")
         case Foos.F => println("dogpig")
doSmth: (foo: Foos.EnumVal)Unit

//But if you don't care about getting exhaustiveness warnings, you can do:

object Foos extends Enum {
  case class EnumVal private[Foos](name: String) extends Value /* { you can define your own methods and stuff here } */

  val F = EnumVal("F")
  val X = EnumVal("X")

Which is a bit less boilerplatey.


More Related questions