As we know, we can add (subtract/multiply/etc.) two numbers of different Numeric types and the result will be the wider of the two types, regardless of their order.
33F + 9L // Float + Long == Float
33L + 9F // Long + Float == Float
This is because each of the 7 Numeric classes (Byte, Short, Char, Int, Long, Float, Double) has 7 different +() methods (and -(), *(), etc), one for every Numeric type that can be received as a passed parameter. [There's an extra +() method for handling a String parameter, but that need not concern us here.]
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 parameter) as it is passed to the +-() method.
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 argument (def +-[U: Numeric](b: U) = ...) because a Numeric, expressed via a type parameter, can only add/subtract it's own type.
Is the only solution to create 7 different classes (PlusOrMinusShort/Int/Long/etc.) with 7 different methods (def +-(b:Short), def +-(b:Int), def +-(b:Long), etc.)?