6

If I have code like 5 * 5.0 the result gets converted to the most accurate type, Double.

But this doesn't seem to work with code like

case class Value[T : Numeric](value: T) {
    type This = Value[T]
    def +(m: This) = Value[T](implicitly[Numeric[T]].plus(value, m.value))
    ...
}

implicit def numToValue[T : Numeric](v: T) = Value[T](v)

Is there a way to make things like someIntValue + double work, where someIntValue is Value[Int] and double is Double?

PS: Sorry for the far less-than-perfect title. I'm thankful for suggestions for better wording ...

soc
  • 27,983
  • 20
  • 111
  • 215
  • 1
    There is also http://stackoverflow.com/questions/3088979/how-to-set-up-implicit-conversion-to-allow-arithmetic-between-numeric-types which might be useful. – Rex Kerr Oct 03 '11 at 04:57

1 Answers1

5

You can do this (with a lot of busywork) by creating implicit operators:

abstract class Arith[A,B,C] {
  def +(a: A, b: B): C
  def -(a: A, b: B): C
  def *(a: A, b: B): C
  def /(a: A, b: B): C
}
implicit object ArithIntLong extends Arith[Int,Long,Long] {
  def +(a: Int, b: Long) = a+b
  def -(a: Int, b: Long) = a-b
  def *(a: Int, b: Long) = a*b
  def /(a: Int, b: Long) = a/b
}
...
def f[A,B,C](a: A, b: B)(implicit arith: Arith[A,B,C]) = arith.*(a,b)


scala> f(5,10L)
res46: Long = 50

but you really have to do more than that, since you need a Numeric equivalent for A and B alone, and the asymmetric operations need to be defined both ways. And it's not really practical to specialize given that there are three types involved.

Rex Kerr
  • 166,841
  • 26
  • 322
  • 407
  • Mhhh .... is this really that uncommon problem that there is no better solution? Another huge problem with this solution is that we actually can't know (and therefore cover) all types conforming to `Numeric[T]`. – soc Oct 03 '11 at 04:41
  • 1
    @soc - It really is that bad. The problem is that `Numeric` provides no way to tell the relative precision of the three types. You could make `Arith` simply a converter from `A` or `B` to `C`, and then have `C` be `Numeric`, and do all your math as a `C`. This would reduce the boilerplate, but you'd still have to write the implicit converters. – Rex Kerr Oct 03 '11 at 04:51