2

So, implicit precedence is based on two factors: one is about the scope of declaration itself having precedence (scope A extending scope/trait B, or scope A being a companion object of a type extended from a type with scope B as its companion object). The other simply mentions that declaration A is more specific than declaration B. Now, when reading it for the first time I had several possible interpretations in mind, especially considering potential parameters (implicit and not) of implicit method and type parameters. Experience seemed to teach me that it means that the type of the returned value by declaration A, after all type inference/tapply, is a subtype of the return type of declaration B. So, this is fine:

  class A
  class B extends A
  implicit val A = new A
  implicit val B = new B
  implicitly[A]

Why this doesn't compile, then?

    implicit class A(val toInt :Int) {
        def ! = (1 /: (2 to toInt))(_ * _)
    }
    implicit class B(i :Int) extends A(i)
    1.!

When this does?

    class A(val toInt :Int) {
        def ! = (1 /: (2 to toInt))(_ * _)
    }
    class B(i :Int) extends A(i)

    implicit val A = { i :Int => new A(i) }
    implicit val B = { i :Int => new B(i) }
    1.!

Is it another case of 'the compiler works in mysterious ways'?

Turin
  • 2,208
  • 15
  • 23

1 Answers1

3

Based on SIP-13 - IMPLICIT CLASSES proposal your declaration:

implicit class A(val toInt :Int) {
    def ! = (1 /: (2 to toInt))(_ * _)
}

Will be transformed to something like:

class A(toInt: Int) {
 ...
}
implicit final def A(toInt: Int): A = new A(toInt);

And your B in its turn will be transformed to something like:

class B(i: Int) extends A(i) {
 ...
}
implicit final def B(i: Int): B = new B(i);

So you are basically declaring 2 implicit conversion methods with the same parameters which are ambiguous. While the last one is not ambiguous due to already mentioned "most specific" rule for implicit parameters resolution.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • I am afraid I did not understand why the last one isn't ambiguous. An implicit method is reified to an implicit function (in Scala 2), so I fail to see where exactly the difference lies, semantically. Also, if I put the implicit class declarations in separate contexts, but then import them (so they are borh identifiers available in the local syntactical context without prefixing), the failing example works: https://stackoverflow.com/questions/69966645/can-i-introduce-an-implicit-precedence-relation-between-packages-as-with-objects – Turin Nov 16 '21 at 18:57
  • @Turin _"I am afraid I did not understand why the last one isn't ambiguous."_ - it is according to the rules you have mentioned in the question (resolution of implicit parameters). And the first one is analogous to selecting method overload based on parameter types. Also see answers to [this](https://stackoverflow.com/q/27875519/2501279) question, your workaround is mentioned there.. – Guru Stron Nov 17 '21 at 19:22