Scala sealed trait - replicate Enumeration `withName` method

Viewed 755

I'm trying to refactor an Enumeration to a sealed trait with concrete classes because I need to pack more functionality into them. With the sealed trait, I'd like to have functionality similar to Enumeration's withName(String) method. I've come up with the following code to do so and am looking for feedback:

sealed trait Foo {
  def name: String
}

object Foo {
  case object FooA extends Foo {
    override val name: String = "a"
  }

  case object FooB extends Foo {
    override val name: String = "b"
  }

  val values = Seq(FooA, FooB)

  def withName(name: String): Option[Foo] = {
    values.find(value => value.name.equals(name))
  }
}

I can then use the withName(String) method to get the corresponding concrete object of type Foo as an Option:

val testFooAName = "a"
val testFooA = Foo.withName(testFooAName) // Will yield Some(FooA)

testFooA match {
    case Some(Foo.FooA) => println("Matched Foo.FooA!")
    case Some(Foo.FooB) => print("Matched Foo.FooB!")
}

val testFooNoneName = "none"
val testFooNone = Foo.withName(testFooNoneName) // Will yield None

Output:
Matched Foo.FooA!

Is this approach correct?

2 Answers

Yes, it looks fine

Minor simplification: Have a map for fast lookup

val values = Seq(FooA, FooB)
val fastLookup = values.map(v => v.name -> v).toMap

def withName(name: String): Option[Foo] = fastLookup.get(name)

There is a handy library by beachape which can be used to provide some of the functionality of enums to your sealed trait

the package you need to include in your sbt is:

"com.beachape" %% "enumeratum" % "1.5.15"

then extend your your object with the Enum like so:

import enumeratum._

sealed trait Foo

object Foo extends Enum[Foo] {
  case object FooA extends Foo 
  case object FooB extends Foo 
}

The you can use the withName function (amongst others) to get the sealed trait you want:

Foo.withName("FooA")
Related