The code snippet below is taken from this ScalaZ tutorial.
I cannot figure out how the implicit resolution rules are applied when evaluating 10.truthy
at the bottom of the code example.
Things that - I think - I do understand are the following:
1) The implicit value intCanTruthy
is an instance of an anonymous subclass of CanTruthy[A]
which defines the truthys
method for Int
-s according to :
scala> implicit val intCanTruthy: CanTruthy[Int] = CanTruthy.truthys({
case 0 => false
case _ => true
})
intCanTruthy: CanTruthy[Int] = CanTruthy$$anon$1@71780051
2) The toCanIsTruthyOps
implicit conversion method is in scope when evaluating 10.truthy
, so the compiler will try to use this implicit conversion method when it sees that Int
does not have a truthy
method. So the compiler will try to look for some implicit conversion method which converts 10
into an object that does have a truthy
method and therefor it will try toCanIsTruthyOps
to this conversion that.
3) I suspect that the implicit value intCanTruthy
somehow might be used when the compiler tries the toCanIsTruthyOps
implicit conversion on 10
.
But this is where I really get lost. I just don't see how the implicit resolution process proceeds after this. What happens next ? How and Why ?
In other words, I don't know what is the implicit resolution sequence that allows the compiler to find the implementation of the truthy
method when evaluating 10.truthy
.
Questions:
How will 10
be converted to some object which does have the correct truthy
method ?
What will that object be ?
Where will that object come from?
Could someone please explain, in detail, how the implicit resolution takes place when evaluating 10.truthy
?
How does the self-type { self => ...
in CanTruthy
play a role in the implicit resolution process ?
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait CanTruthy[A] { self =>
/** @return true, if `a` is truthy. */
def truthys(a: A): Boolean
}
object CanTruthy {
def apply[A](implicit ev: CanTruthy[A]): CanTruthy[A] = ev
def truthys[A](f: A => Boolean): CanTruthy[A] = new CanTruthy[A] {
def truthys(a: A): Boolean = f(a)
}
}
trait CanTruthyOps[A] {
def self: A
implicit def F: CanTruthy[A]
final def truthy: Boolean = F.truthys(self)
}
object ToCanIsTruthyOps {
implicit def toCanIsTruthyOps[A](v: A)(implicit ev: CanTruthy[A]) =
new CanTruthyOps[A] {
def self = v
implicit def F: CanTruthy[A] = ev
}
}
// Exiting paste mode, now interpreting.
defined trait CanTruthy
defined module CanTruthy
defined trait CanTruthyOps
defined module ToCanIsTruthyOps
Trying out the type class on 10
:
scala> import ToCanIsTruthyOps._
import ToCanIsTruthyOps._
scala> implicit val intCanTruthy: CanTruthy[Int] = CanTruthy.truthys({
case 0 => false
case _ => true
})
intCanTruthy: CanTruthy[Int] = CanTruthy$$anon$1@71780051
scala> 10.truthy
res6: Boolean = true