Reputation: 4573
I am a complete Scala and Akka newbie, and am teaching myself the language by building an order book for equity trading. The core of my order book will be two PriorityQueues: one for bids and one for asks.
val bids = new mutable.PriorityQueue[Bid]()(BidOrdering)
val asks = new mutable.PriorityQueue[Ask]()(AskOrdering)
My idea is to define special BidOrdering
and AskOrdering
for these queues so that price and time priority will be maintained for bids and asks of various types. However I am having trouble defining the Ordering
classes.
Here is 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 bids of type LimitOrder. However my issue is that there will be many types of Bid
in my model and I want to define BidOrdering
in such a way that it could be used to order collections of various sub-types of Bids
. I think it would look something like...
object BidOrdering extends Ordering[Bid] {
def compare(first:Bid, second:Bid) = first compare second
}
}
Upvotes: 3
Views: 547
Reputation: 139038
You're on the right track—you just need to describe how to compare the 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 clearly and concisely):
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.
Upvotes: 2