scala - возможно ли навязать неизменность объекта? - PullRequest
3 голосов
/ 07 декабря 2011

Я имею в виду, если есть какой-то декларативный способ предотвратить изменение объекта любым из его членов.

В следующем примере

class student(var name:String)

val s = new student("John")

"s" был объявлен как val, поэтому он всегда будет указывать на одного и того же студента.

Но есть ли способ предотвратить изменение s.name, просто объявив его неизменным ???

Или единственное решение - объявить все как val и вручную принудительно установить неизменность?

Ответы [ 3 ]

6 голосов
/ 07 декабря 2011

Нет, невозможно объявить что-то неизменное. Вы должны сами установить неизменность, не позволяя никому изменять ее, то есть удалить все способы изменения класса.

Кто-то может изменить его, используя отражение, но это уже другая история.

2 голосов
/ 07 декабря 2011

Scala не применяет это, поэтому нет способа узнать.Есть, однако, интересный проект плагин компилятор под названием pusca (я думаю, что это означает Pure-Scala).Чистый определяется здесь как не изменяющий нелокальную переменную и не имеющий побочных эффектов (например, не печатающий на консоль) - так что повторный вызов чистого метода всегда будет давать один и тот же результат (то, что называется ссылочно-прозрачным).

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

1 голос
/ 08 декабря 2011

В общем случае 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:

  1. someFunctionOfStudent принимает произвольного студента и не реализован в этом модуле компиляции.Он был написан / скомпилирован, зная, что Student состоит из двух изменяемых полей.Откуда мы знаем, что это на самом деле не мутирует их?
  2. genericHigherOrderFunction еще хуже;он будет принимать Student и функцию Student, но он написан полиморфно.Мутирует ли он на самом деле s, зависит от других его аргументов;определение того, что во время компиляции с полной общностью требует решения проблемы остановки.
  3. Давайте предположим, что мы можем обойти это (возможно, мы могли бы установить некоторые секретные флаги, которые означают, что исключения возникают, если объект s действительно мутирован,хотя лично я не нашел бы это достаточно хорошим).Как насчет этого поля course?course.someMethod() мутирует это?Этот вызов метода не вызывается из s напрямую.
  4. Хуже того, мы знаем только, что мы передадим экземпляр Course или некоторый подкласс из Course.Поэтому, даже если мы сможем проанализировать конкретную реализацию Course и Course.someMethod и сделать вывод, что это безопасно, кто-то всегда может добавить новый подкласс Course, реализация которого someMethod мутирует Course.

Компилятор просто не может проверить, что данный объект не может быть изменен.Плагин pusca, упомянутый 0__, похоже, обнаруживает чистоту так же, как и Меркурий;гарантируя, что каждый метод известен из его сигнатуры как чистый или нечистый, и вызывая ошибку компилятора, если реализация чего-либо, объявленного чистым, делает все, что может вызвать нечистоту (если программист не обещает, чтометод в любом случае чистый). [1]

Это совсем не то, что просто объявлять значение полностью (и глубоко) неизменным и ожидать, что компилятор заметит, может ли какой-нибудь код, который может его коснуться,мутировать его.Это также не идеальный вывод, просто консервативный

[1] pusca README утверждает, что он может вывести нечистоту методов, последнее выражение которых является вызовом нечистого метода.Я не совсем уверен, как это может сделать это, поскольку проверка того, является ли последнее выражение нечистым вызовом, требует проверки, вызывает ли он метод not-Объявленный-нечистый, который должен быть объявлен нечистым по этому правилу, и реализация может быть недоступнак компилятору в этот момент (и действительно может быть изменен позже, даже если это так).Но все, что я сделал, это посмотрел на README и подумал об этом несколько минут, чтобы я мог что-то упустить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...