I have a class with a parameterized type that I want to do comparison operators on. I assmue I need to use the Ordered trait to achieve this but the compiler doesn\'t like my us
This occurs because Int
is not a subclass of Ordered[Int]
(see here why).
However, there is an implicit coercion from Int
to RichInt
which is a subclass of Ordered[Int]
, but it isn't triggered for lower bounds. Use <%
(view bounds) instead which will consider implicit coercions:
class Test[T <% Ordered[T]]
You can use the Ordering[T] type class as an implicit parameter. If you wanted to write a generic max function, it would look like this:
def max[T](a:T, b:T)(implicit ordering:Ordering[T]) = {
if(ordering.gt(a,b)) a else b
}
For the primitive data types like Int, Float, ..., there is an implicit Ordering[T] in scope so that you can use this as you would expect.
max(1,2) // gives 2
For all types that implement Ordered[T], there is also an implicit to provide an Ordering[T].
There are also various methods in scope that combine orderings. For example if you have a N-tuple where each element has an Ordering[T], there automatically exists an Ordering for the tuple type.
max((1,2), (3,4)) // gives (3,4) because 3 is larger than 1
But if you are not satisfied with any of the implicitly provided orderings you can just write your own and pass it explicitly or even get it in scope as an implicit val. Like this:
val negativeIntOrdering = new Ordering[Int] {
def compare(a:Int,b:Int) = b - a
}
max(1,2)(negativeIntOrdering) // gives 1
So the typeclass based approach is much more flexible than the inheritance based approach. This is why math libraries like spire use it extensively.
One thing that is not as nice about the code above is that you have to use the lt method instead of an operator. But there is a solution for that as well. Ordering has an implicit method called mkOrderingOps that provides operators for T. You just need to get it in scope by importing ordering._, like this:
def max[T](a:T, b:T)(implicit ordering:Ordering[T]) = {
import ordering._;
if(a>b) a else b
}