object Suit extends Enumeration {
type Suit = Value
val Spades, Hearts, Diamonds, Clubs = Value
}
I won't go into the details of the syntax of this (I don't understand it myself!) but I will observe that this mechanism works reasonably well. The only odd thing here is that if you actually want to refer to Spades, for instance, in your code, you will need to write something like this:
import Suit._
But you will find that the suit values have an ordering that you would expect without you having to do anything about it, as in this bit of Scalatest code for instance:
"suits" should "be ordered properly" in {
val suitList = List(Clubs,Hearts,Spades,Diamonds)
suitList.sorted shouldBe List(Spades,Hearts,Diamonds,Clubs)
}
But what if we want to know the color of a suit? How can we add a method to this enumeration (in a manner similar to the way it is done in Java?). It's tricky! -- my first (obvious) attempt did not succeed. I am indebted to Aaron Novstrup and StackOverflow for this somewhat elegant solution:
object Suit extends Enumeration {
type Suit = Value
val Spades, Hearts, Diamonds, Clubs = Value
class SuitValue(suit: Value) {
def isRed = !isBlack
def isBlack = suit match {
case Clubs | Spades => true
case _ => false
}
}
implicit def value2SuitValue(suit: Value) = new SuitValue(suit)
}
So, let's implement our suits again:
trait Concept extends Ordered[Concept] {
val name: String
val priority: Int
override def toString = name
def compare(that: Concept) = priority-that.priority
}
object Concept {
implicit def ordering[A <: Concept]: Ordering[A] = Ordering.by(_.priority)
}
sealed trait Suit extends Concept {
def isRed = !isBlack
def isBlack = this match {
case Spades | Clubs => true
case _ => false
}
}
case object Spades extends Suit { val name = "Spades"; val priority = 3 }
case object Hearts extends Suit { val name = "Hearts"; val priority = 2 }
case object Diamonds extends Suit { val name = "Diamonds"; val priority = 1 }
case object Clubs extends Suit { val name = "Clubs"; val priority = 0 }
If you decide to implement this without trait Concept and simply defining its methods directly in Suit, you would find that you do not need to define any implicit ordering. However, in order to sort a list of suits, you would have to explicitly define the type of your list as for example:
List[Suit](Clubs,Spades)
This is because Suit appears as Suit with Product etc. This is the kind of thing that makes working with implicit values so tricky.
If you'd like to see the code for all this, including unit tests, then go to my Scalaprof site on github. and drill down to edu.neu.coe.scala.enums.
No comments:
Post a Comment