jwvh - 11 months ago 47

Scala Question

As we know, we can add (subtract/multiply/etc.) two numbers of different

`Numeric`

`33F + 9L // Float + Long == Float`

33L + 9F // Long + Float == Float

This is because each of the 7

`Numeric`

`Byte`

`Short`

`Char`

`Int`

`Long`

`Float`

`Double`

`+()`

`-()`

`*()`

`Numeric`

`+()`

`String`

Now consider the following:

`implicit class PlusOrMinus[T: Numeric](a: T) {`

import Numeric.Implicits._

def +-(b: T) = if (util.Random.nextBoolean) a+b else a-b

}

This works if the two operands are the same type, but it also works if the type of the 1st operand is wider than the type of the 2nd.

`11F +- 2L // result: Float = 9.0 or 13.0`

I believe what's happening here is that the compiler uses weak conformance to achieve numeric widening on the 2nd operand (the

`b`

`+-()`

But the 1st operand won't be widened to match the 2nd. It won't even compile.

`11L +- 2F // Error: type mismatch; found: Float(2.0) required: Long`

Is there any way around this limitatiion?

I can't use a different type parameter for the

`b`

`def +-[U: Numeric](b: U) = ...`

`Numeric`

Is the only solution to create 7 different classes (

`PlusOrMinusShort/Int/Long/`

`def +-(b:Short)`

`def +-(b:Int)`

`def +-(b:Long)`

Answer Source

Here is a way:

```
implicit class PlusOrMinus[T: Numeric](a: T) {
import Numeric.Implicits._
def +-(b: T) = plusOrMinus(a,b)
def +-[U: Numeric](b: U)(implicit ev: T => U) = plusOrMinus[U](a,b)
private def plusOrMinus[W: Numeric](a: W, b: W): W =
if (util.Random.nextBoolean) a+b else a-b
}
```

Then, with this, I get the following interaction:

```
scala> 11F +- 2L
res0: Float = 9.0
scala> 11L +- 2F
res1: Float = 9.0
```

The idea is that if I could just have a function `plusOrMinus`

, this whole problem would be trivial, since the same widening could happen for either arguments. After defining such a function, the problem becomes how to embed it into an implicit class to use it in an infix form.

Here, we have only two cases: either the second argument needs to be widened or the argument wrapped by the implicit class needs to be widened. The first of these cases is covered by the first `+-`

method (for the reasons you observed above). For the second, however, we need to explicitly say that there is some conversion that is possible and pass the generic type of the conversion to `plusOrMinus`

.