Почему этот явный вызов метода Scala позволяет неявно разрешать его?

Почему этот код не скомпилирован, но успешно компилируется, когда я раскомментирую указанную строку? (Я использую Scala 2,8 в ночное время). Кажется, что явно вызов string2Wrapper позволяет использовать его неявно с этой точки.

class A {
  import Implicits.string2Wrapper
  def foo() {
     //string2Wrapper("A") ==> "B" // <-- uncomment
  } 
  def bar() {
    "A" ==> "B"
    "B" ==> "C"
    "C" ==> "D"
  }
  object Implicits {
    implicit def string2Wrapper(s: String) = new Wrapper(s)
    class Wrapper(s: String) {
      def ==>(s2: String) {}
    }
  }
}

Изменить: спасибо за ответы до сих пор, в том числе указатель на комментарий Мартина Одерского,

"Неявное преобразование без явного типа результата видимо только в тексте следуя собственному определению. Таким образом, мы избегаем циклических ошибок ссылки.

Мне все равно было бы интересно узнать 1), какова опасность "циклических эталонных ошибок"?, и 2) Почему явный вызов имеет какое-то значение?

Ответы

Ответ 1

Явная привязка возвращаемого типа string2Wrapper устраняет проблему.

class A {
  import Implicits._

  def bar() {    
    "A" ==> "B"
    "B" ==> "C"
    "C" ==> "D"
  }
  object Implicits {
    implicit def string2Wrapper(s: String): Wrapper = new Wrapper(s)
    class Wrapper(s: String) {
      def ==>(s2: String) {}
    }
  }
}

Определение Implicits до bar также работает:

class A {
  object Implicits {
    implicit def string2Wrapper(s: String) = new Wrapper(s)
    class Wrapper(s: String) {
      def ==>(s2: String) {}
    }
  }

  import Implicits._

  def bar() {    
    "A" ==> "B"
    "B" ==> "C"
    "C" ==> "D"
  } 
}

Если вам нужно полагаться на неявное преобразование, определенное ниже в текущей области, убедитесь, что вы аннотируете его тип возврата. Довольно точно, что это появилось в списках рассылки раньше, и может ожидаться поведение, а не ошибка. Но я не могу найти его в данный момент. Я предполагаю, что явный вызов в foo запускает вывод типа возвращаемого типа bar, который тогда действителен при вводе содержимого bar.

UPDATE

В чем опасность циклической ошибки ссылки?

Тело неявного метода может вызывать метод, который требует неявного преобразования. Если у обоих из них есть предполагаемый тип возврата, вы находитесь в тупике. Это не применяется в вашем примере, но компилятор не пытается обнаружить это.

Почему явный вызов имеет значение?

Явный вызов ранее запускает вывод типа возвращаемого типа неявного метода. Здесь логика в Implicits.isValid

sym.isInitialized ||
      sym.sourceFile == null ||
      (sym.sourceFile ne context.unit.source.file) || 
      hasExplicitResultType(sym) ||
      comesBefore(sym, context.owner)

ОБНОВЛЕНИЕ 2

Эта недавняя ошибка выглядит актуальной: https://lampsvn.epfl.ch/trac/scala/ticket/3373

Ответ 2

Если бы вы были просто ооооодно ночью позже, вы бы вместо этого увидели сообщение об ошибке, которое я добавил вчера.

<console>:11: error: value ==> is not a member of java.lang.String
 Note: implicit method string2Wrapper is not applicable here because it comes after the application point and it lacks an explicit result type
           "A" ==> "B"
           ^
<console>:12: error: value ==> is not a member of java.lang.String
 Note: implicit method string2Wrapper is not applicable here because it comes after the application point and it lacks an explicit result type
           "B" ==> "C"
           ^
<console>:13: error: value ==> is not a member of java.lang.String
 Note: implicit method string2Wrapper is not applicable here because it comes after the application point and it lacks an explicit result type
           "C" ==> "D"
           ^

Ответ 3

Если вы положили object Implicits во-первых, он работает. Это выглядит как ошибка для меня в логике для создания нескольких прогонов компилятора; он предполагает, что он может уйти, не зная о string2Wrapper при компиляции bar. Я предполагаю, что, если вы его используете, он знает, что не может уйти, не зная, что такое string2Wrapper, на самом деле компилирует Implicits, а затем понимает, что ==> неявно определяется в String.

Изменить: на основании того, что опубликовал Retronym, возможно, это "функция", а не ошибка. Мне все еще кажется нелепым!