An implicit question to newcomers to Scala seems to be: where does the compiler look for implicits? I mean implicit because the question never seems to get fully formed, as if there weren’t words for it. 🙂 For example, where do the values for integral below come from?
scala> import scala.math._
import scala.math._
scala> def foo[T](t: T)(implicit integral: Integral[T]) {println(integral)}
foo: [T](t: T)(implicit integral: scala.math.Integral[T])Unit
scala> foo(0)
scala.math.Numeric$IntIsIntegral$@3dbea611
scala> foo(0L)
scala.math.Numeric$LongIsIntegral$@48c610af
Another question that does follow up to those who decide to learn the answer to the first question is how does the compiler choose which implicit to use, in certain situations of apparent ambiguity (but that compile anyway)?
For instance, scala.Predef defines two conversions from String: one to WrappedString and another to StringOps. Both classes, however, share a lot of methods, so why doesn’t Scala complain about ambiguity when, say, calling map?
Note: this question was inspired by this other question, in the hopes of stating the problem in a more general manner. The example was copied from there, because it is referred to in the answer.
Types of Implicits
Implicits in Scala refers to either a value that can be passed "automatically", so to speak, or a conversion from one type to another that is made automatically.
Implicit Conversion
Speaking very briefly about the latter type, if one calls a method
mon an objectoof a classC, and that class does not support methodm, then Scala will look for an implicit conversion fromCto something that does supportm. A simple example would be the methodmaponString:Stringdoes not support the methodmap, butStringOpsdoes, and there’s an implicit conversion fromStringtoStringOpsavailable (seeimplicit def augmentStringonPredef).Implicit Parameters
The other kind of implicit is the implicit parameter. These are passed to method calls like any other parameter, but the compiler tries to fill them in automatically. If it can’t, it will complain. One can pass these parameters explicitly, which is how one uses
breakOut, for example (see question aboutbreakOut, on a day you are feeling up for a challenge).In this case, one has to declare the need for an implicit, such as the
foomethod declaration:View Bounds
There’s one situation where an implicit is both an implicit conversion and an implicit parameter. For example:
The method
getIndexcan receive any object, as long as there is an implicit conversion available from its class toSeq[T]. Because of that, I can pass aStringtogetIndex, and it will work.Behind the scenes, the compiler changes
seq.IndexOf(value)toconv(seq).indexOf(value).This is so useful that there is syntactic sugar to write them. Using this syntactic sugar,
getIndexcan be defined like this:This syntactic sugar is described as a view bound, akin to an upper bound (
CC <: Seq[Int]) or a lower bound (T >: Null).Context Bounds
Another common pattern in implicit parameters is the type class pattern. This pattern enables the provision of common interfaces to classes which did not declare them. It can both serve as a bridge pattern — gaining separation of concerns — and as an adapter pattern.
The
Integralclass you mentioned is a classic example of type class pattern. Another example on Scala’s standard library isOrdering. There’s a library that makes heavy use of this pattern, called Scalaz.This is an example of its use:
There is also syntactic sugar for it, called a context bound, which is made less useful by the need to refer to the implicit. A straight conversion of that method looks like this:
Context bounds are more useful when you just need to pass them to other methods that use them. For example, the method
sortedonSeqneeds an implicitOrdering. To create a methodreverseSort, one could write:Because
Ordering[T]was implicitly passed toreverseSort, it can then pass it implicitly tosorted.Where do Implicits come from?
When the compiler sees the need for an implicit, either because you are calling a method which does not exist on the object’s class, or because you are calling a method that requires an implicit parameter, it will search for an implicit that will fit the need.
This search obey certain rules that define which implicits are visible and which are not. The following table showing where the compiler will search for implicits was taken from an excellent presentation (timestamp 20:20) about implicits by Josh Suereth, which I heartily recommend to anyone wanting to improve their Scala knowledge. It has been complemented since then with feedback and updates.
The implicits available under number 1 below has precedence over the ones under number 2. Other than that, if there are several eligible arguments which match the implicit parameter’s type, a most specific one will be chosen using the rules of static overloading resolution (see Scala Specification §6.26.3). More detailed information can be found in a question I link to at the end of this answer.
Same scope in other filesLet’s give some examples for them:
Implicits Defined in Current Scope
Explicit Imports
Wildcard Imports
Same Scope in Other Files
Edit: It seems this does not have a different precedence. If you have some example that demonstrates a precedence distinction, please make a comment. Otherwise, don’t rely on this one.
This is like the first example, but assuming the implicit definition is in a different file than its usage. See also how package objects might be used in to bring in implicits.
Companion Objects of a Type
There are two object companions of note here. First, the object companion of the "source" type is looked into. For instance, inside the object
Optionthere is an implicit conversion toIterable, so one can callIterablemethods onOption, or passOptionto something expecting anIterable. For example:That expression is translated by the compiler to
However,
List.flatMapexpects aTraversableOnce, whichOptionis not. The compiler then looks insideOption‘s object companion and finds the conversion toIterable, which is aTraversableOnce, making this expression correct.Second, the companion object of the expected type:
The method
sortedtakes an implicitOrdering. In this case, it looks inside the objectOrdering, companion to the classOrdering, and finds an implicitOrdering[Int]there.Note that companion objects of super classes are also looked into. For example:
This is how Scala found the implicit
Numeric[Int]andNumeric[Long]in your question, by the way, as they are found insideNumeric, notIntegral.Implicit Scope of an Argument’s Type
If you have a method with an argument type
A, then the implicit scope of typeAwill also be considered. By "implicit scope" I mean that all these rules will be applied recursively — for example, the companion object ofAwill be searched for implicits, as per the rule above.Note that this does not mean the implicit scope of
Awill be searched for conversions of that parameter, but of the whole expression. For example:This is available since Scala 2.9.1.
Implicit Scope of Type Arguments
This is required to make the type class pattern really work. Consider
Ordering, for instance: It comes with some implicits in its companion object, but you can’t add stuff to it. So how can you make anOrderingfor your own class that is automatically found?Let’s start with the implementation:
So, consider what happens when you call
As we saw, the method
sortedexpects anOrdering[A](actually, it expects anOrdering[B], whereB >: A). There isn’t any such thing insideOrdering, and there is no "source" type on which to look. Obviously, it is finding it insideA, which is a type argument ofOrdering.This is also how various collection methods expecting
CanBuildFromwork: the implicits are found inside companion objects to the type parameters ofCanBuildFrom.Note:
Orderingis defined astrait Ordering[T], whereTis a type parameter. Previously, I said that Scala looked inside type parameters, which doesn’t make much sense. The implicit looked for above isOrdering[A], whereAis an actual type, not type parameter: it is a type argument toOrdering. See section 7.2 of the Scala specification.This is available since Scala 2.8.0.
Outer Objects for Nested Types
I haven’t actually seen examples of this. I’d be grateful if someone could share one. The principle is simple:
Other Dimensions
I’m pretty sure this was a joke, but this answer might not be up-to-date. So don’t take this question as being the final arbiter of what is happening, and if you do noticed it has gotten out-of-date, please inform me so that I can fix it.
EDIT
Related questions of interest: