Determining the order of subtypes in Scala
I am a complete newbie to Scala and Akka and I am teaching the language itself by creating an order book for stock trading. The core of my order book will be two PriorityQueues, one for bids and one for requests.
val bids = new mutable.PriorityQueue[Bid]()(BidOrdering)
val asks = new mutable.PriorityQueue[Ask]()(AskOrdering)
My idea - to determine special BidOrdering
and AskOrdering
for those queues to maintain the price and time priority for rates and different types of queries. However, I find it difficult to define the classes Ordering
.
Here's an example (adapted from the scala docs ) that demonstrates the problem more clearly ...
import scala.util.Sorting
case class LimitOrderBid(quantity:Long, limit:Double)
val bids = Array(LimitOrderBid(100, 30.0), LimitOrderBid(10, 32.3), LimitOrderBid(1, 19))
// sort by limit price
object BidOrdering extends Ordering[LimitOrderBid] {
def compare(a:LimitOrderBid, b:LimitOrderBid) = a.limit compare b.limit
}
Sorting.quickSort(bids)(BidOrdering)
The above works for proposals like LimitOrder. However, my problem is that there will be many types in my model Bid
, and I want to define BidOrdering
in such a way that it can be used to order collections of different subtypes Bids
. I think it will look like ...
object BidOrdering extends Ordering[Bid] {
def compare(first:Bid, second:Bid) = first compare second
}
}
source to share
You are on the right track - you just need to describe how to compare different combinations of subtypes. For example:
sealed trait Base
case class Foo(i: Int) extends Base
case class Bar(s: String) extends Base
case class Qux(f: Double) extends Base
object Base {
implicit object orderingBase extends Ordering[Base] {
def compare(first: Base, second: Base) = (first, second) match {
// First describe how to compare pairs of the same type
case (Foo(i1), Foo(i2)) => i1 compare i2
case (Bar(s1), Bar(s2)) => s1 compare s2
case (Qux(f1), Qux(f2)) => f1 compare f2
// Every Foo precedes any non-Foo
case (Foo(_), _) => -1
case (_, Foo(_)) => 1
// Every Bar precedes any Qux
case (Bar(_), Qux(_)) => -1
case (Qux(_), Bar(_)) => 1
}
}
}
Or (a little more clear and concise):
sealed trait Base
case class Foo(i: Int) extends Base
case class Bar(s: String) extends Base
case class Qux(f: Double) extends Base
object Base {
implicit val orderingBase: Ordering[Base] = Ordering.fromLessThan {
// First describe how to compare pairs of the same type
case (Foo(i1), Foo(i2)) => i1 < i2
case (Bar(s1), Bar(s2)) => s1 < s2
case (Qux(f1), Qux(f2)) => f1 < f2
// Every Foo precedes any non-Foo
case (Foo(_), _) => true
case (_, Foo(_)) => false
// Every Bar precedes any Qux
case (Bar(_), Qux(_)) => true
case (Qux(_), Bar(_)) => false
}
}
If your parent type is sealed, you'll get a nice error message if you miss a case.
source to share