Scala resolution of several implicit parameters

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 IntLike exists only to convince me that this is not an Int focused issue.

This seems pretty standard, if bad, using implicits, and I expected it to work happily. However, when calling purchaseCandles() REPL gives the following error:

error: ambiguous implicit values: both StringCanBuildFrom values ​​in the Predef object of type => scala.collection.generic.CanBuildFrom [String, Char, String] and the guest value of the Tree type corresponds to the expected type A

For life, I cannot see how this happens. A must have an IntLike view IntLike , the type I just came up with. REPL confirms that there is no hidden view:

scala> implicitly [Tree => IntLike]

res14: Tree => IntLike = function1

but

scala> implicitly [scala.collection.generic.CanBuildFrom [String, Char, String] => IntLike]

: 18: error: implicit view is available from scala.collection.generic.CanBuildFrom [String, Char, String] => IntLike.

So, how StringCanBuildFrom be of the appropriate type? Is the compiler capable of resolving multiple dependent implications, and if not, why is this error displayed?

+4
source share
2 answers

Before proceeding with the answer, here is the first case given. Note that you invoke purchaseCandles without any hint of type A , which in my opinion is the source of the problem.

 object Foo def test[A <% Foo.type](implicit bar: A) {} test 

Error:

 <console>:10: error: ambiguous implicit values: both value StringCanBuildFrom in object Predef of type => scala.collection.generic.CanBuildFrom[String,Char,String] and method conforms in object Predef of type [A]=> <:<[A,A] match expected type A test ^ 

StringCanBuildFrom seems more like a confused error message. If you concentrate on conforms here, the reason why this does not work may become clearer: Predef.conform states that whenever you request an implicit conversion A => A , this is guaranteed by identification. This is so that if you have def foo[B <% A](b: B) , you can always call foo with a value of type A without having to define any type of A => A


You are requesting the resolution of an implicit argument of an unspecified type along with a conversion from this unspecified type to IntLike . I think this goes beyond the implicit resolution algorithm. However, the error message is somewhat strange.

+1
source

There is still no explanation why this fails - although, as I said, I expect it to be too much for implicit permission due to the undefined input type, but you can make it work like this:

  implicit def findIntLike[A <% IntLike](x: A): IntLike = x def purchaseCandles()(implicit age: IntLike) = { println(s"I'm going to buy $age candles!") } implicit val guest = Tree(50) purchaseCandles() 
0
source

Source: https://habr.com/ru/post/1469513/


All Articles