Yann Moisan
Yann Moisan

Reputation: 8281

Scala enumeration and group of values

I need to group some values of an Enumeration.

Here is the code :

object PostType extends Enumeration {
  // Documents
  val BOOKMARK = Value("bookmark")
  val FILE = Value("file")
  val NOTE = Value("note")
  val WIKIDOC = Value("wikidoc")

  …    
}

object PostTypes {
  type PostTypes = List[PostType.Value]
  val DOCUMENTS : PostTypes = List(PostType.BOOKMARK, PostType.FILE, PostType.NOTE, PostType.WIKIDOC)
  val QUESTIONS : PostTypes = List(PostType.QUESTION, PostType.QUICKPOLL, PostType.SURVEY)
  val EVENT : PostTypes = List(PostType.EVENT)
  …
  val ALL : PostTypes = PostType.values.toList
}

Is there a better way ? Here are the cons that I see : PostType.Value and PostTypes.PostTypes in client code !

[update] improve code with the help of both answers

object PostType extends Enumeration {
  // Documents
  val Bookmark = Value("bookmark")
  val File = Value("file")
  val Note = Value("note")
  val Wikidoc = Value("wikidoc")
  …
}

object PostTypes {
  import PostType._
  implicit def toList(pt: Value) = List(pt)

  type PostTypes = List[Value]
  val Documents = List(Bookmark, File, Note, Wikidoc)
  val Questions = List(Question, Quickpoll, Survey)
  val All = values.toList
}

[update 2] Another bunch of improvements

object PostType extends Enumeration {
  type PostType = Value
  type PostTypes = List[Value]

  implicit def toList(pt: Value) = List(pt)

  // Documents
  val Bookmark = Value(1, "bookmark")
  val File = Value(2, "file")
  val Note = Value(3, "note")
  val Wikidoc = Value(12, "wikidoc")

  // Declare after Val to avoid runtime error
  val Documents = List(Bookmark, File, Note, Wikidoc)
  val Questions = List(Question, Quickpoll, Survey)
  val All = values.toList.sorted
}

Upvotes: 1

Views: 2179

Answers (3)

Yann Moisan
Yann Moisan

Reputation: 8281

Here is the final code, with the help of other answers. Just need to import PostType._ in client code.

object PostType extends Enumeration {
  type PostType = Value
  type PostTypes = List[Value]

  implicit def toList(pt: Value) = List(pt)

  // Documents
  val Bookmark = Value(1, "bookmark")
  val File = Value(2, "file")
  val Note = Value(3, "note")
  val Wikidoc = Value(12, "wikidoc")

  // Declare after Val to avoid runtime error
  val Documents = List(Bookmark, File, Note, Wikidoc)
  val Questions = List(Question, Quickpoll, Survey)
  val All = values.toList.sorted
}

Upvotes: 0

Dave Swartz
Dave Swartz

Reputation: 910

Below is an approach that does not use enumerations, but hopefully achieves your aims. The example shows how to instantiate PostType from a String instance. If the String does not match then a MatchError is thrown.

package rando

object PostType {
  val all = Document.all ++ Question.all
  def fromString(s: String): PostType = Document.fromString.orElse(Question.fromString)(s)
}
sealed trait PostType

object Document {
  val all = Set(Bookmark, File, Note, Wikidoc)
  val fromString: PartialFunction[String, Document] = {
    case "bookmark" => Bookmark
    case "file" => File
    case "note" => Note
    case "wikidoc" => Wikidoc
  }
}
sealed trait Document extends PostType
case object Bookmark extends Document
case object File extends Document
case object Note extends Document
case object Wikidoc extends Document

object Question {
  val all = Set(SlowPoll, QuickPoll, Survey)
  val fromString: PartialFunction[String, Question]  = {
    case "slowpoll" => SlowPoll
    case "quickpoll" => QuickPoll
    case "survey" => Survey
  }
}
sealed trait Question extends PostType
case object SlowPoll extends Question
case object QuickPoll extends Question
case object Survey extends Question

object Example extends App {
  println(PostType.fromString("bookmark").getClass)
}

Upvotes: 3

yǝsʞǝla
yǝsʞǝla

Reputation: 16422

I think it's as good as it gets unless you want to use alternative Enumeration implementation (see my answer here) or just use some constants.

The only thing I could suggest is to define a type alias type PostType = Value and use it instead of Value. I'm sure you know that by importing <package>.PostType._ you won't have to prefix your enum values with PostType anymore.

Finally PostTypes seems a little bit like overkill and it's easy to confuse it with PostType when reading. These are just minor things though. I use the same approach as you do and I'm not aware of anything better.

Upvotes: 2

Related Questions