简体   繁体   中英

Case object enumerations, order and implicits

For pedagogical purposes I have implemented an enumeration using both Enumeration and case objects. I'm comfortable with the Enumeration version, although it cannot warn of missing cases in a match statement.

I have tried to write the equivalent using case objects but I am finding that, although it compiles, it doesn't run. In particular, it seems to go into an infinite loop at run time (I haven't been able to confirm this in the debugger, however). Here's the code I'm trying to run:

sealed abstract class Suit extends Ordered[Suit] {
  val name: String
  val priority: Int
  override def toString = name
  def compare(that: Suit) = priority-that.priority
}
case object Spades extends Suit { val name = "Spades"; val priority = 0 }
case object Hearts extends Suit { val name = "Hearts"; val priority = 1 }
case object Diamonds extends Suit { val name = "Diamonds"; val priority = 2 }
case object Clubs extends Suit { val name = "Clubs"; val priority = 3 }

object Suit {
  implicit def ordering[A <: Suit]: Ordering[A] = Suit.ordering
  def suits = List(Clubs,Spades).sorted
}

If I enter this code into the REPL (via paste mode) or if I compile it in Eclipse, all appears well. But if I try to test the suits method of the Suit object, the run just hangs and I have to terminate it.

I have tried most if not all of the suggestions I've found here on StackOverflow regarding implicits (for instance, not defining Suit class to extend Ordered[Suit] and instead specifying an Ordering directly for the class. None of these have compiled however.

Working suggestions much appreciated.

object Suit {
  implicit def ordering[A <: Suit]: Ordering[A] = Suit.ordering
}

That is an infinite loop, ordering calls itself. I think you want an Ordering[Suit] , it doesn't make sense in this case to ask for an ordering of a sub-type A of Suit (that would be one individual case object).

There is already an implicit ordering for types that extend Ordered , so you won't even need to construct one:

implicitly[Ordering[Suit]]  // aka Ordering.ordered[Suit]

So the following just works:

object Suit {
  def suits = List[Suit](Clubs, Spades).sorted
}

Note that List(Clubs, Spades).sorted won't work, because the inferred list element type is Suit with Product and somehow that produces a failure to find an unambiguous ordering.

Part of the problem that I had before was that Suit actually extends a trait called Concept, which I hadn't shown here (in an attempt to simplify things).

However, it actually allows a slight improvement on 0__'s answer because I no longer have to explicitly set the type of my list. Here is the code, at least the relevant parts:

trait Concept extends Ordered[Concept]{
  val name: String
  val priority: Int
  override def toString = name
  def compare(that: Concept) = priority-that.priority
}
sealed trait Suit extends Concept {
}
object Concept {
  implicit def ordering[A <: Concept]: Ordering[A] = Ordering.by(_.priority)
}
case object Spades extends Suit { val name = "Spades"; val priority = 0 }
case object Hearts extends Suit { val name = "Hearts"; val priority = 1 }
case object Diamonds extends Suit { val name = "Diamonds"; val priority = 2 }
case object Clubs extends Suit { val name = "Clubs"; val priority = 3 }
object Suit {
  import scala.math.Ordered.orderingToOrdered
  def suits = List(Clubs,Spades).sorted
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM