Неявная конверсия странности

Я пытаюсь понять, почему именно неявное преобразование работает в одном случае, но не в другом. Вот пример:

   case class Wrapper[T](wrapped: T)
   trait Wrapping { implicit def wrapIt[T](x: Option[T]) = x.map(Wrapper(_))

   class NotWorking extends Wrapping { def foo: Option[Wrapper[String]] = Some("foo") }

   class Working extends Wrapping { 
      def foo: Option[Wrapper[String]] = {
        val why = Some("foo")
        why
      }
    }

В принципе, у меня есть неявное преобразование от Option[T] до Option[Wrapper[T]], и я пытаюсь определить функцию, которая возвращает необязательную строку, которая неявно завернута.

Вопрос в том, почему, когда я пытаюсь вернуть Option[String] напрямую (NotWorking выше), я получаю сообщение об ошибке (found : String("foo") required: Wrapper[String]), которое исчезает, если я передам результат val, прежде чем возвращать его.

Что дает?

Ответ 1

Я не знаю, было ли это предназначено или будет считаться ошибкой, но вот что я думаю, что происходит.

В def foo: Option[Wrapper[String]] = Some("foo") компилятор задает ожидаемый тип аргумента, предоставленного Some( ), как Wrapper[String]. Затем он видит, что вы предоставили String, который не является ожидаемым, поэтому он ищет неявное преобразование String => Wrapper[String], не может найти его и терпит неудачу.

Зачем ему нужен этот тип ожидаемого типа и не просто набирает Some("foo") как Some[String], а потом пытается найти преобразование? Поскольку scalac хочет иметь возможность проверять следующий код:

case class Invariant[T](t: T)
val a: Invariant[Any] = Invariant("s")

Чтобы этот код работал, компилятор не может просто набрать Invariant("s") как Invariant[String], потому что тогда компиляция завершится неудачно, поскольку Invariant[String] не является подтипом Invariant[Any]. Компилятору необходимо установить ожидаемый тип "s" на Any, чтобы он мог видеть, что "s" является экземпляром Any до того, как он слишком поздно.

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

Причина, по которой ваш код Working работает, заключается в том, что такой тип вывода не охватывает несколько строк. Аналогично val a: Invariant[Any] = {val why = Invariant("s"); why} не компилируется.