Определение значений экземпляра Scala
Note that this question and similar ones have been asked before, such as in Прямые ссылки - почему этот код компилируется?, но я нашел ответы, чтобы все еще оставить некоторые вопросы открытыми, поэтому у меня есть другой подход к этому вопросу.
В рамках методов и функций, эффект отval
Ключевое слово выглядит как лексическое, т.е.
<code>def foo { println(bar) val bar = 42 } </code>
получая
<code>error: forward reference extends over definition of value bar </code>
Тем не менее, в классах, обзорные правилаval
кажется, измениться:
<code>object Foo { def foo = bar println(bar) val bar = 42 } </code>
Это не только компиляция, но иprintln
в конструкторе будет давать0
как его вывод, при вызовеfoo
после того, как экземпляр полностью построен, получится ожидаемое значение42
.
Таким образом, представляется возможным для методов пересылать ссылки на значения экземпляров, которые, в конечном итоге, будут инициализированы до вызова метода (если, конечно, вы не вызываете его из конструктора), а также для операторов внутри конструктора направлять ссылочные значения таким же образом, получая доступ к ним до их инициализации, что приводит к глупому произвольному значению.
Отсюда возникает пара вопросов:
Why doesval
use its lexical compile-time effect within constructors?
Учитывая, что конструктор - это на самом деле всего лишь метод, это кажется довольно непоследовательным, чтобы полностью отброситьval
'Эффект времени компиляции, придающий ему только обычный эффект времени выполнения.
val
, effectively, lose its effect of declaring an immutable value?
Доступ к значению в разное время может привести к разным результатам. Для меня это очень похоже на утечку деталей реализации компилятора.
What might legitimate usecases for this look like?Мне трудно придумать пример, который абсолютно требует текущей семантикиval
внутри конструкторов и не могут быть легко реализованы с помощью правильной, лексическойval
возможно в сочетании сlazy
.
val
, getting back all the guarantees one is used to from using it within other methods?
Можно, по-видимому, объявить все инстанцииval
с бытьlazy
чтобы вернуться кval
быть неизменным и давать один и тот же результат, независимо от того, как к ним осуществляется доступ, и сделать эффект времени компиляции, наблюдаемый в обычных методах, менее актуальным, но это кажется мне ужасным хаком для такого рода вещей.
Учитывая, что это поведение вряд ли когда-либо изменится в реальном языке, будет ли плагин компилятора подходящим местом для решения этой проблемы, или возможно ли реализоватьval
-подобное ключевое слово с, для кого-то, кто только что потратил час на отладку проблемы, вызванной этой странностью, более разумной семантики в языке?