I was always figuring implicit conversions over multiple levels is not possible in scala (unless you define view bounds: http://docs.scala-lang.org/tutorials/FAQ/context-and
As Gabor already commented, this is due to numeric widening. If you run with the -print option, you will see that a .toDouble is appended to the i, which then allows it to use the toA implicit. You can run scalac with the warn-numeric-widen and this will at least give you the following:
<console>:14: warning: implicit numeric widening
println(i.total) //Why does this work?
^
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,toDoubledefined 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.