The point of implicit stuff is to fill in boring boilerplate stuff when there is clearly only one right way to do it.
In the case of implicit parameters the compiler inserts a parameter from context that must be what you were thinking of. For example,
case class TaxRate(rate: BigDecimal) { }
implicit var sales_tax = TaxRate(0.075)
def withTax(price: BigDecimal)(implicit tax: TaxRate) = price*(tax.rate+1)
scala> withTax(15.00)
res0: scala.math.BigDecimal = 16.1250
Since we've marked the tax rate as an implicit parameter, and provided an implicit variable that can be filled in when needed, we don't need to specify the tax rate. The compiler automatically fills in withTax(15.00)(sales_tax)
In the case of implicit conversions, the compiler looks for a method that can take a type that it has and convert it to the type that is needed. This conversion cannot be chained under normal circumstances, so you have to get to what you need in one step.
There are two cases where implicit conversions are likely to come into play. One is in the parameter of a method call--if the type is wrong, but it can be converted to the right type (in exactly one way), then the compiler will convert for you. The other is in the presence of a method call--if the type actually used doesn't have the method available, but you could convert it to a type that does have that method, then the conversion will take place and then the method will be called.
Let's look at an example of each.
implicit def float2taxrate(f: Float) = TaxRate(BigDecimal(f))
scala> withTax(15.00)(0.15f)
res1: scala.math.BigDecimal = 17.250000089406967200
Here, we call an explicit tax rate of 0.15f
. That doesn't match the parameter, which must be of type TaxRate
, but the compiler sees that we can turn floats into tax rates using the implicit float2taxrate
. So it does it for us, calling withTax(15.00)(float2taxrate(0.15f))
Now the other example.
class Currency(bd: BigDecimal) {
def rounded = bd.setScale(2,BigDecimal.RoundingMode.HALF_EVEN)
}
implicit def bigdec2currency(bd: BigDecimal) = new Currency(bd)
scala> withTax(15.00)(0.15f).rounded
res66: scala.math.BigDecimal = 17.25
BigDecimal doesn't have a rounded
method, so withTax(15.00)(0.15f)
shouldn't be able to call one (as it returns a BigDecimal
). But we've defined a Currency
that does have a rounded
method, and a conversion to Currency
, so the implicit conversion fills in all the details: bigdec2currency(withTax(15.00)(0.15f)).rounded
.
In the case of the conversion from Int
to BigInt
, the compiler will use it when, for example, it tries to add 7 + BigInt(5)
. This isn't going to work normally--7
is an Int
and Int
doesn't know how to add itself to BigInt
. But BigInt
has a method +
that can add itself to another BigInt
. And the compiler sees that if only it could convert 7
to a BigInt
, it could use that method. The implicit conversion allows that conversion, so it translates 7 + BigInt(5)
into int2bigInt(7)+BigInt(5)
.
(Note: int2bigInt
is defined inside BigInt
, so to use it you have to import BigInt._
. And it in turn defers to the apply(i: Int)
method of the BigInt
object, which is what lets you write BigInt(5)
and have it work (rather than having to pass a string as with BigInteger
in Java).)