First, implicit parameters are not the same as implicit object conversions. Implicit parameters provide a way to allow parameters of a method to be "found". This is similar to default parameters at a glance but in fact is a different mechanism for finding the "default" value. It differs from implicit object conversion in that it is only a way for parameters for a method to be resolved. Implicit object conversion allows methods to appear to be called on one object when in fact that object is being converted behind the scenes to another type. (more or less)
An implicit parameter is a parameter to method or constructor that is marked as implicit. This means that if a parameter value is not supplied then the compiler will search for an "implicit" value defined within scope (according to resolution rules.) Implicit parameter resolution rules will be discussed soon.
Example:
- scala> def p(implicit i:Int) = print(i)
- p: (implicit i: Int)Unit
- // defining a val/var/def as implicit
- // means that it will be considered during implicit resolution
- scala> implicit val v=2
- v: Int = 2
- // scope is searched for a implicit value to sue
- // v is found as marked implicit
- scala> p
- 2
- // explicit declarations always overrides implicit values
- scala> p(1)
- 1
Implicit parameters are very nice for simplifying APIs. For example the collections use implicit parameters to supply CanBuildFrom objects for many of the collection methods. This is because normally the user does not need to be concerned with those parameters. Another example is supplying an encoding to an IO library so the encoding is defined once (perhaps in a package object) and all methods can use the same encoding without having to define it for every method call.
One important restriction is that there can only be a single implicit keyword per method. It must be at the start of a parameter list (which also makes all values of that parameter list be implicit). I further understand that only the last parameter list may be implicit.
Here are several illegal examples:
- // implicit is not in last parameter list
- scala> def pp(implicit i:Int, a:Int)(b:Int) = println(a,i)
- < console>:1: error: '=' expected but '(' found.
- def pp(implicit i:Int, a:Int)(b:Int) = println(a,i)
- // there are 2 implicit parameters
- scala> def pp(implicit j:Int, a:Int)(implicit i:Int,b:Int) = println(a,i)
- < console>:1: error: '=' expected but '(' found.
- def pp(implicit j:Int, a:Int)(implicit i:Int,b:Int) = println(a,i)
- // implicit is not the first parameter of the parameter list
- scala> def pp(a:Int, implicit i:Int) = println(i,j)
- < console>:1: error: identifier expected but 'implicit' found.
- def pp(a:Int, implicit i:Int) = println(i,j)
- ^
Here are several legal examples (Updated with useage examples):
- scala> implicit def v = 7
- v: Int
- scala> implicit var x = 10L
- x: Long
- // i is implicit
- scala> def pp(a:Int)(implicit i:Int) = println(a,i)
- pp: (a: Int)(implicit i: Int)Unit
- scala> pp(3)
- (3,7)
- // both i and b are implicit
- scala> def pp(a:Int)(implicit i:Int, b:Long) = println(a,i,b)
- pp: (a: Int)(implicit i: Int,implicit b: Long)Unit
- scala> pp(4)
- (4,7,10)
- // both i and b are implicit
- scala> def pp(implicit i:Int, b:Long) = println(i,b)
- pp: (implicit i: Int,implicit b: Long)Unit
- scala> pp
- (7,10)
- // all or none of the parameters must be supplied
- scala> pp(2)
- < console>:13: error: not enough arguments for method pp: (implicit i: Int,implicit b: Long)Unit.
- Unspecified value parameter b.
- pp(2)
- // This is syntactically legal but I cannot seem to implicitly invoke this
- // I would recommend: def pp(b:Long*)(implicit i:Int) = println(i,b)
- scala> def pp(implicit i:Int, b:Long*) = println(i,b)
- pp: (implicit i: Int,implicit b: Long*)Unit
- scala> pp(3,1,2,3)
- (3,WrappedArray(1, 2, 3))
- scala> def pp(b:Long*)(implicit i:Int) = println(i,b)
- pp: (b: Long*)(implicit i: Int)Unit
- scala> pp(1,2,3)
- (7,WrappedArray(1, 2, 3))
A related topic is Companion Object implicits.
Thanks for this (as for all your posts). What does def pp(a:Int)(implicit i:Int, b:Long) = println(a,i,b) define, and how would you use it? Are both i and b implicit, or just i? Thanks
ReplyDeleteExcellent questions. I have updated the post with answers (I hope :) )
ReplyDeleteExcellent post, as usual! You stated that "One important restriction is that there can only be a single implicit parameter per method" but then show several examples that actually have several implicit parameters. I think it might technically be more accurate to note that the implicit keyword applies to the entire last argument list, however long it is, instead of just to a single parameter.
ReplyDeleteAs you can see. I occasionally/often am figuring out the rules as I write the post. In this case I figured out what was going on thanks to future examples but forgot to correct that statement.
ReplyDeleteI have updated the post with more accurate information
Thanks nice code comments
ReplyDeleteThank u. You explained the concept very well.
ReplyDeleteThanks, great explanation, very well written.
ReplyDelete