In trying to answer this question, I came up with the following code:
case class Monkey(bananas: Int)
case class Tree(rings: Int)
case class Duck(quacks: Seq[String])
implicit class IntLike(val x : Int) extends AnyVal
implicit def monkey2Age(monkey: Monkey): IntLike = monkey.bananas / 1000
implicit def tree2Age(tree: Tree): IntLike = tree.rings
implicit def duck2Age(duck: Duck): IntLike = duck.quacks.size / 100000
def purchaseCandles[A <% IntLike]()(implicit age : A) = {
val asAge : IntLike = age
println(s"I'm going to buy $asAge candles!")
}
{
implicit val guest = Tree(50)
purchaseCandles()
}
Note that the IntLike
is only there to convince me this wasn't a problem focussed on Int
.
This seems a fairly standard, if bad, use of implicits, and I was expecting it to work happily. However, on invoking purchaseCandles()
the REPL yields the following error:
error: ambiguous implicit values: both value StringCanBuildFrom in object Predef of type => scala.collection.generic.CanBuildFrom[String,Char,String] and value guest of type Tree match expected type A
I cannot for the life of me see how this is the case. A is bound to have an view bound of IntLike
, a type I just invented. The REPL confirms that there is no implicit view available:
scala> implicitly[Tree => IntLike]
res14: Tree => IntLike = function1
but
scala> implicitly[scala.collection.generic.CanBuildFrom[String, Char, String] => IntLike]
:18: error: No implicit view available from scala.collection.generic.CanBuildFrom[String,Char,String] => IntLike.
So how can StringCanBuildFrom
be of an appropriate type? Is the compiler capable of resolving the multiple dependent implicits, and if not, why is this the error being shown?