Reputation: 11542
I'm writing a little script evaluator function. It takes two arguments and a comparison operator like this:
def compare[T,U](a:T, op:String, b:U): Boolean = {
op match {
case "==" => a == b
case "<" => a < b
// and so on with other comparators...
}
}
This code won't compile. The '<' operator doesn't work on the generic types. I couldn't find a parent class for numeric types with the '<' operator, so I can't even do something like: def compare[T<:Numeric,U<:Numeric](...)
Is there a way to do this (or a library)? Right now I can only test equal/not-equal.
Upvotes: 5
Views: 396
Reputation: 159
edit: Luis' answer involving using a single parameter type and relying on type inference is likely the best overall solution. If you are set on using two separate types, here are some options:
Since you are attempting to compare two separate classes, you cannot directly inherit a trait member implementation that will fit both. However, if you can provide function literals that will convert a class to a Double, you can use the following code.
def compare[T,U](a: T, op:String, b: U, tToDouble: T => Double, uToDouble: U => Double): Boolean = {
op match {
case "==" => tToDouble(a) == uToDouble(b)
case "<" => tToDouble(a) < uToDouble(b)
// and so on with other comparators...
}
}
//example using Int
println(compare(1, "<", 2, (x:Int) => x.toDouble, (y:Int) => y.toDouble)) //true
Unfortunately, we cannot use Ordering or Numeric, because those are parameterized traits and the expectation is for comparison against themselves. Another method is just to accept a comparator function that accepts objects of each type whenever you wish to compare two types of objects.
def compare[T,U](a: T, op:String, b: U, comparator: (T,U) => Int): Boolean = {
op match {
case "==" => comparator(a,b) == 0
case "<" => comparator(a,b) < 0
// and so on with other comparators...
}
}
println(compare[Int, Int](1, "<", 2, (a,b) => a-b)) //true
Upvotes: 2
Reputation: 22895
In general, every time you want some kind of interface for common operations on multiple types, the answer is a Typeclass.
In this particular case, you can use scala.math.Ordering
.
import scala.math.Ordering
import Ordering.Implicits._
def compare[T: Ordering](a: T, op: String, b: T): Boolean = op match {
case "==" => a == b
case "<" => a < b
// and so on with other comparators...
}
And now you can use it like this.
compare(10, "==", 15) //false
compare(10, "==", 10) // true
compare(10, "<", 10) // false
compare(10, "<", 11) // true
Upvotes: 6