Обратите внимание, если это подходит для вас, но в функциональных языках, таких как Standard ML, все по умолчанию неизменяемо. Мутация поддерживается через универсальный ref
тип erence. Таким образом, int
переменная является неизменной, а ref int
переменная является изменяемым контейнером для int
s. По сути, переменные - это реальные переменные в математическом смысле (неизвестное, но фиксированное значение), а ref
s - это «переменные» в смысле императивного программирования - ячейка памяти, в которую можно записывать и читать. (Мне нравится называть их назначаемыми .)
Я думаю, что проблема с const
двоякой. Во-первых, в C ++ отсутствует сборщик мусора, который необходим для создания нетривиальных постоянных структур данных . const
должен быть глубоким, чтобы иметь какой-либо смысл, но иметь полностью неизменные значения в C ++ нецелесообразно.
Во-вторых, в C ++ вам нужно выбирать, const
а не отказываться от него. Но когда вы const
что-то забудете, а потом исправите, вы окажетесь в ситуации «отравления константой», упомянутой в ответе @ RobY, где const
изменение будет касаться всего кода. Если бы это const
было по умолчанию, вы бы не подали заявку const
задним числом. Кроме того, необходимость добавлять const
везде добавляет много шума в код.
Я подозреваю, что основные языки, которые последовали (например, Java), были в значительной степени сформированы успехом и мышлением C и C ++. Например, даже при сборке мусора большинство API-интерфейсов по сбору языков предполагают изменяемые структуры данных. Тот факт, что все является изменчивым и неизменным, рассматривается как крайний случай, что многое говорит о императивном мышлении, стоящем за популярными языками.
РЕДАКТИРОВАТЬ : После размышления на комментарии Greenoldman я понял, что const
это не напрямую об неизменности данных; const
кодирует в тип метода, имеет ли он побочные эффекты на экземпляре.
Возможно использование мутации для достижения ссылочно прозрачного поведения. Предположим, у вас есть функция, которая при последовательном вызове возвращает разные значения - например, функция, которая читает один символ stdin
. Мы могли бы использовать кеш / запоминать результаты этой функции для создания ссылочно прозрачного потока значений. Поток будет связанным списком, чьи узлы будут вызывать функцию при первой попытке получить их значение, но затем кэшировать результат. Так что, если stdin
constains Hello, world!
, первый раз , когда вы пытаетесь получить значение первого узла, он будет прочитать одно char
и возвращение H
. После этого он продолжит возвращаться H
без дальнейших звонков, чтобы прочитать char
. Аналогично, второй узел будет читать char
изstdin
в первый раз вы пытаетесь получить его значение, на этот раз возвращаете e
и кешируете этот результат.
Интересно то, что вы превратили процесс, который по своей сути является состоянием, в объект, который кажется не имеющим состояния. Однако, чтобы достичь этого, необходимо было изменить внутреннее состояние объекта (путем кэширования результатов) - мутация была благоприятным эффектом . Невозможно сделать наш, CharStream
const
даже если поток ведет себя как неизменное значение. Теперь представьте, что есть Stream
интерфейс с const
методами, и все ваши функции ожидают const Streams
. Вы CharStream
не можете реализовать интерфейс!
( РЕДАКТИРОВАТЬ 2: Очевидно, есть ключевое слово C ++ mutable
, которое позволит нам обманывать и делатьCharStream
const
. Однако, эта лазейка разрушает const
гарантии - теперь вы действительно не можете быть уверены, что что-то не будет мутировать через его const
методы. Я полагаю, что это не так плохо, так как вы должны явно просить лазейку, но вы все еще полностью полагаетесь на систему чести.)
Во-вторых, предположим, что у вас есть функции высокого порядка, то есть вы можете передавать функции в качестве аргументов другим функциям. const
Ness является частью сигнатуры функции, поэтому вы не сможете передавать не- const
функции в качестве аргументов функциям, ожидающим const
функции. Слепое соблюдение const
здесь приведет к потере общности.
Наконец, манипулирование const
объектом не гарантирует, что он не мутирует какое-то внешнее (статическое или глобальное) состояние за вашей спиной, поэтому const
гарантии не так сильны, как они изначально кажутся.
Мне не ясно, что кодирование наличия или отсутствия побочных эффектов в системе типов - это всегда хорошая вещь.