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.)?