Can an implicit conversion of an implicit value correspond to an implicit parameter?

I define some Scala implicits to make it easier to work with a specific immutable set of Java classes. The following Scala code is a simplified example that obviously looks crazy, in the real world I am trying to carry certain resources (rather than a numeric age) implicitly from Monkey, Tree and Duck for use in various methods such as purchaseCandles()

 // actually 3 Java classes I can not change: case class Monkey(bananas: Int) case class Tree(rings: Int) case class Duck(quacks: Seq[String]) // implicits I created to make my life easier... implicit def monkey2Age(monkey: Monkey): Int = monkey.bananas / 1000 implicit def tree2Age(tree: Tree): Int = tree.rings implicit def duck2Age(duck: Duck): Int = duck.quacks.size / 100000 // one of several helper methods that I would like to define only once, // only useful if they can use an implicit parameter. def purchaseCandles()(implicit age: Int) = { println(s"I'm going to buy $age candles!") } // examples of usage { implicit val guest = Monkey(10000) purchaseCandles() } { implicit val guest = Tree(50) purchaseCandles() } { implicit val guest = Duck(Seq("quack", "quack", "quack")) purchaseCandles() } 

A compiler error that occurs 3 times:

 could not find implicit value for parameter age: Int purchaseCandles() ^ 

Leaving aside many different ways in which this sample code is crazy, my real question is: can implicit conversions of implicit values โ€‹โ€‹match implicit parameters in Scala?

+1
source share
2 answers

The short answer is no. The Scala compiler will only look to apply one implicit, so if it does not detect an implicit int lying around, it will stop and give up.

However, you can write your purchaseCandles method to work with types that can be converted to Int , and require a parameter of this type:

 def purchaseCandles[A <% Int]()(implicit age : A) = { val asAge : Int = age println(s"I'm going to buy $asAge candles!") } 

The asAge part asAge necessary to enforce implicit conversion.

At present, it seems to me that I need to specify type A in this scenario, although I cannot understand why: since there should not be other values โ€‹โ€‹around types that can be implicitly converted to Int (this happens with completely new types, therefore this is not the ubiquity of Int .) But you can do:

 { implicit val guest = Monkey(10000) purchaseCandles[Monkey]() } 

This use of implicits, however, is probably bad ideas!

+5
source

You really can do this: you just need to mark the parameters of your implicit conversion as implicit:

 implicit def monkey2Age(implicit monkey: Monkey): Int = monkey.bananas / 1000 implicit def tree2Age(implicit tree: Tree): Int = tree.rings implicit def duck2Age(implicit duck: Duck): Int = duck.quacks.size / 100000 

This will bind the implicates the way you want.

As always: Beware, he will also do it where you do not want it. By the way, I highly recommend an implicit parameter of type Int (or its implicit value). This is just too general. (I assume this is the case as in your example).

+1
source

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


All Articles