I want to define a collection class and require its element being Ordered
Considering the code below:
class MyCollection[K: Ordered[K]] {
def func(seq: Seq[K]): Unit = {
seq.sorted
}
}
The compiler will report error No implicit Ordering defined for ord: Ordering[K]
Am I doing anything wrong? Given that we already have the constraint K: Ordered[K]
You should use:
either Ordered
with
class MyCollection[K <: Ordered[K]] {
def func(seq: Seq[K]): Unit =
seq.sorted
}
class MyCollection[K](implicit ev: K <:< Ordered[K]) {
def func(seq: Seq[K]): Unit =
seq.sorted
}
class MyCollection[K](implicit ev: K => Ordered[K]) {
def func(seq: Seq[K]): Unit =
seq.sorted
}
(from stronger to weaker assumption)
or Ordering
with context bound
class MyCollection[K: Ordering] {
def func(seq: Seq[K]): Unit =
seq.sorted
}
Ordered
and Ordering
are now defined so that the constraints K => Ordered[K]
and K: Ordering
are actually equivalent. Indeed, Ordering.ordered
transforms one into another in one direction, Ordered.orderingToOrdered
transforms in the other
def test[K](implicit ev: K => Ordered[K]) =
implicitly[Ordering[K]] // compiles
def test[K: Ordering] =
implicitly[K => Ordered[K]] // compiles
The context bound MyCollection[K: Ordering]
is a syntax sugar for MyCollection[K](implicit ev: Ordering[K])
.
That's why [K: Ordered[K]]
can't compile at all because of kind mismatch.
Ordering
is a type class but Ordered
is not. Ordered
is an ordinary OOP trait (you're extending it in OOP style rather than define its implicit instances in FP style).
That's why although [K: Ordered]
compiles but it would be incorrect semantically (implicits will not be found).
Ordering and Ordered and comparing Options