1

I have this fairly simple example where one function foo(), which takes an implicit argument of type A, tries to call another function bar(), which takes an implicit argument of type B. In the project where I ran into this question, B contains a subset of the functionality of A, so I would like to provide an implicit conversion from A to B to make cases like in this example seamless.

Implementing this using the implicit conversion B.implicitConversion() works as expected. The following code is accepted by scalac 2.13.0:

trait A

trait B

object B {
  // implicit class ImplicitClass(value: A) extends B

  implicit def implicitConversion(implicit se: A) = ???
}

class Test {
  def foo()(implicit a: A) = bar()

  def bar()(implicit b: B) = ???
}

Oddly enough, implementing the conversion using the implicit class ImplicitClass does not work (by removing the definition of implicitConversion() and adding the definition of ImplicitClass). The code is rejected by scalac:

$ scalac 'Test.scala:12: error: could not find implicit value for parameter b: B
def foo()(implicit a: A) = bar()
^
one error found

I would have assumed that in such a situation implicit classes and implicit conversion are interchangeable. What am I missing here, why are the two ways of providing a conversion not equivalent?

Feuermurmel
  • 9,490
  • 10
  • 60
  • 90
  • 2
    Implicit classes are only used for **extension methods** not for **implicit conversions**, since in the place where it has to find the _implicits_ you are not directly calling any method of the `B` class, then it is not used. Wheres, the implicit conversion will be applied. - Note that, implicit conversions are discouraged for very good reasons. It would be better if you do this instead `trait A extends B`. This way, if you have an instance of `A` it can be used where a `B` is expected due the **Liskov** principle. – Luis Miguel Mejía Suárez Jun 20 '19 at 15:25
  • 2
    @LuisMiguelMejíaSuárez 1. No, they can be used for implicit conversions. 2. "you are not directly calling any method of the B class" But the expected type IS `B`, which can trigger the implicit conversion. – Alexey Romanov Jun 20 '19 at 21:20

1 Answers1

2

ImplicitClass is equivalent to

class ImplicitClass(value: A) extends B

implicit def ImplicitClass(value: A): ImplicitClass

You can see the difference: this implicit conversion takes value: A as an explicit parameter, unlike your def implicitConversion. And if you change to

def foo()(implicit a: A) = bar()(a)

you'll see it work.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487