Implicits are sought among all methods and values that are visible in the current scope AND within companion objects of types that appear in the implicit type you are looking for.
implicit val a: A = ???
implicit val bc: B[C] = ???
// code here sees a and bc in implicit scope
def helper = {
implicit val c: C = ???
// code here sees a and bc and c in implicit scope
}
def anotherHelper = {
val a: A = ??? // overshades a
// code here sees b in implicit scope
}
object Helper {
implicit val e: E = ???
// code here sees a, bc and e in implicit scope
}
// implicits within helper, anotherHelper and Helper are not seen here
// though Helper one's can be imported with import Helper._
class D[T]
object {
implicit def provide[T](implicit a: T): D[T] = ???
}
class E
object E {
implicit val e: E = ???
}
class F
object F
// sees no implicits that are always available but
// if you require implicitly[E], E companion will be searched
// and implicit e will be found
// if you require implicitly[D[F]], both D and F companions
// will be searched, D.provide[F] will require implicit F,
// and no such implicit will be found - failure
If you asked for implicit A[B, C, (D, E), F[G]]
, then Scala would look into companions of A
, B
, C
, D
, E
, Tuple2
, F
, G
(if they exist). If this rule doesn't apply (your implicits aren't in companion, your type doesn't appear in sought implicit) you have to import them manually.
When Scala sees that you try to call a method on object that doesn't exists, it will try to convert it to some object which has this method. If you have some X
type, it will look for implicits your X
and returning some Y
(implicit defs(x: X): Y
and implicit val f: X => Y
) and checking if that Y
has this method.
Implicit class is basically a combination of a class and implicit method:
// implicit class Y(x: X) is the same as
class Y(x: X)
implicit def convert(x: X): Y = new Y(x)
which means that you can add some implicit conversions/classes from type X
into X
's companion and they will be always available.
In docs:
implicit class IntWithTimes(x: Int)
created implicit conversion from Int => IntWithTimes
. String
doesn't have times
method, but there is a conversion Int => IntWithTimes
in implicit scope imperted with import Helper._
(without it compilation would fail). Its result, IntWithTimes
has the times
method with the right signature, so the conversion is used.