В общем случае Scala не может это сделать.
Рассмотрим следующий гипотетический пример:
class Student(var name : String, var course : Course)
def stuff(course : Course) {
magically_pure_val s = new Student("Fredzilla", course)
someFunctionOfStudent(s)
genericHigherOrderFunction(s, someFunctionOfStudent)
course.someMethod()
}
Подводные камни для любой попытки фактически реализовать это ключевое слово magically_pure_val
:
someFunctionOfStudent
принимает произвольного студента и не реализован в этом модуле компиляции.Он был написан / скомпилирован, зная, что Student
состоит из двух изменяемых полей.Откуда мы знаем, что это на самом деле не мутирует их? genericHigherOrderFunction
еще хуже;он будет принимать Student
и функцию Student
, но он написан полиморфно.Мутирует ли он на самом деле s
, зависит от других его аргументов;определение того, что во время компиляции с полной общностью требует решения проблемы остановки. - Давайте предположим, что мы можем обойти это (возможно, мы могли бы установить некоторые секретные флаги, которые означают, что исключения возникают, если объект
s
действительно мутирован,хотя лично я не нашел бы это достаточно хорошим).Как насчет этого поля course
?course.someMethod()
мутирует это?Этот вызов метода не вызывается из s
напрямую. - Хуже того, мы знаем только, что мы передадим экземпляр
Course
или некоторый подкласс из Course
.Поэтому, даже если мы сможем проанализировать конкретную реализацию Course
и Course.someMethod
и сделать вывод, что это безопасно, кто-то всегда может добавить новый подкласс Course
, реализация которого someMethod
мутирует Course
.
Компилятор просто не может проверить, что данный объект не может быть изменен.Плагин pusca, упомянутый 0__, похоже, обнаруживает чистоту так же, как и Меркурий;гарантируя, что каждый метод известен из его сигнатуры как чистый или нечистый, и вызывая ошибку компилятора, если реализация чего-либо, объявленного чистым, делает все, что может вызвать нечистоту (если программист не обещает, чтометод в любом случае чистый). [1]
Это совсем не то, что просто объявлять значение полностью (и глубоко) неизменным и ожидать, что компилятор заметит, может ли какой-нибудь код, который может его коснуться,мутировать его.Это также не идеальный вывод, просто консервативный
[1] pusca README утверждает, что он может вывести нечистоту методов, последнее выражение которых является вызовом нечистого метода.Я не совсем уверен, как это может сделать это, поскольку проверка того, является ли последнее выражение нечистым вызовом, требует проверки, вызывает ли он метод not-Объявленный-нечистый, который должен быть объявлен нечистым по этому правилу, и реализация может быть недоступнак компилятору в этот момент (и действительно может быть изменен позже, даже если это так).Но все, что я сделал, это посмотрел на README и подумал об этом несколько минут, чтобы я мог что-то упустить.