Scala: почему инициализация underscore (_) работает для полей, но не для переменных метода?

это работает:

scala> class foo[T] {
     | var t: T = _
     | }
defined class foo

но это не так:

scala> def foo[T] = {
     |   var t: T = _
     | }
<console>:5: error: local variables must be initialized
         var t: T = _

почему?

(можно использовать:

var t: T = null.asInstanceOf[T]

)

Ответ 1

Существует поток списка рассылки, на который ответил Мартин:

Это соответствует JVM. Вы можете опустить инициализацию поля, но не инициализацию локальной переменной. Опускание локальных инициализаций переменных означает, что компилятор должен иметь возможность синтезировать значение по умолчанию для каждого типа. Это не так просто перед лицом параметров типа, специализации и т.д.

При нажатии на то, как происходит или должно быть какое-либо различие между полями и локалями в вопросе Scala, синтезирующих значения по умолчанию, он продолжал говорить:

В терминах байт-кодов существует явная разница. JVM инициализирует поля объекта по умолчанию и требует, чтобы локальные переменные инициализировались явно. [...] Я не уверен, следует ли нам разбить полезный принцип Java (locals должны быть инициализированы до того, как они будут использованы), или нам лучше пойти на полную длину и внедрить проверку инициализации на основе потоков, как в Java. Это было бы лучшим решением, ИМО, но для этого потребовалась бы значительная работа с точки зрения спецификации и реализации. Столкнувшись с этими выборами, мой естественный инстинкт теперь ничего не делает: -)

Итак, если я правильно понимаю, компилятор Scala фактически не синтезирует значения по умолчанию для полей объекта, он создает байт-код, который оставляет JVM для обработки этого.

В соответствии с SI-4437 было достигнуто согласие Мартина о фактическом одобрении шаблона null.asInstanceOf[T] в спецификации языка, казалось бы, из-за отсутствия способных реально поддерживать лучшую альтернативу в рамках существующих ограничений.

Ответ 2

Это определено в разделе 4.2 Scala Спецификация языка (курсив мой)

Определение переменной var x: T = _ может отображаться только как элемент шаблона. Это вводит изменяемое поле с типом T и начальным значением по умолчанию

Это, конечно, не отвечает, почему это должно быть так!

Ответ 3

Вот как минимум один случай, который я только что открыл. Когда тогда суперкласс инициализирует переменные-члены через отражение, он может фактически инициализировать переменные-члены подкласса. Однако, если подкласс также инициализирует переменную-член со значением, это приведет к перезаписи значения, которое дал ему суперкласс. Этого можно избежать, инициализируя переменную-элемент подкласса с помощью подчеркивания. Вот почему спецификация языка говорит о предоставлении переменной функции getter, которая возвращает текущее значение немного дальше от цитируемого предложения в предложении oxbow_lake.