It happens via a different mechanism, unique to the numeric types, called numeric widening.
SLS 6.26.1 Value Conversions says:
The following five implicit conversions can be applied to an expression e which has some value type T and which is type-checked with some expected type pt.
Static Overloading Resolution
Type Instantiation
Numeric Widening
Numeric Literal Narrowing
Value Discarding
View Application
Dynamic Member Selection
(Okay, that's more than five....not sure why :)
The one of interest is numeric widening:
If e has a primitive number type which weakly conforms to the expected type, it is widened to the expected type using one of the numeric conversion methods toShort
, toChar
, toInt
, toLong
, toFloat
, toDouble
defined here.
3.5.16 Weak Conformance says
In some situations Scala uses a more general conformance relation. A type S weakly conforms to a type T, written S<:wT, if S<:T or both S and T are primitive number types and S precedes T in the following ordering.
Byte <:w Short
Short <:w Int
Char <:w Int
Int <:w Long
Long <:w Float
Float <:w Double
So println(i.total)
becomes println(i.total.toFloat)
because Int <:w <: Long <: Float
.
Java (and C# and many other languages) have numeric widening, and Scala decided to keep it.
Note that the reverse does not work: a Float
cannot be implicitly converted to Int
via this way, since magnitude could be lost; it's not a "widening".
You can add -Ywarn-numeric-widen
and get a warning when this happens.