Неизменяемый объект - Immutable object

В объектно-ориентированный и функциональный программирование, неизменный объект (неизменный[1] объект) является объект состояние которого нельзя изменить после его создания.[2] Это в отличие от изменяемый объект (изменяемый объект), который может быть изменен после его создания. В некоторых случаях объект считается неизменным, даже если некоторые внутренние атрибуты меняются, но состояние объекта кажется неизменным с внешней точки зрения. Например, объект, использующий мемоизация для кэширования результатов дорогостоящих вычислений все еще можно рассматривать как неизменный объект.

Строки и другие конкретные объекты обычно выражаются как неизменяемые объекты, чтобы улучшить читаемость и эффективность выполнения в объектно-ориентированного программирования. Неизменяемые объекты также полезны, потому что они по своей сути потокобезопасный.[2] Другие преимущества заключаются в том, что их проще понять и рассуждать, и они предлагают более высокий уровень безопасности, чем изменяемые объекты.[2]

Концепции

Неизменяемые переменные

В императивное программирование, ценности, хранящиеся в программные переменные чье содержимое никогда не меняется, известны как константы чтобы отличать их от переменных, которые могут быть изменены во время выполнения. Примеры включают коэффициенты преобразования из метров в футы или значение число Пи до нескольких знаков после запятой.

Поля только для чтения могут вычисляться при запуске программы (в отличие от констант, которые известны заранее), но никогда не изменяются после их инициализации.

Слабая и сильная неизменность

Иногда говорят об определенных поля неизменности объекта. Это означает, что нет возможности изменить эти части состояния объекта, даже если другие части объекта могут быть изменены (слабо неизменный). Если все поля неизменяемы, объект неизменен. Если весь объект не может быть расширен другим классом, объект вызывается строго неизменный.[3] Это может, например, помочь явным образом обеспечить соблюдение определенных инвариантов в отношении определенных данных в объекте, которые остаются неизменными в течение всего времени существования объекта. В некоторых языках это делается с помощью ключевого слова (например, const в C ++, окончательный в Ява ), который обозначает поле как неизменяемое. В некоторых языках это наоборот: в OCaml, поля объекта или записи по умолчанию неизменяемы и должны быть явно отмечены изменчивый быть таким.

Ссылки на объекты

В большинстве объектно-ориентированные языки, объекты можно ссылаться с помощью Рекомендации. Некоторые примеры таких языков: Ява, C ++, C #, VB.NET, и много языки сценариев, такие как Perl, Python, и Рубин. В этом случае имеет значение, может ли состояние объекта изменяться при совместном использовании объектов через ссылки.

Ссылки и копирование объектов

Если известно, что объект неизменяем, рекомендуется создать ссылка вместо копирования всего объекта. Это сделано для экономии памяти, предотвращая дублирование данных и избегая вызовов конструкторов и деструкторов; это также приводит к потенциальному увеличению скорости выполнения.

Технику копирования ссылок гораздо сложнее использовать для изменяемых объектов, потому что, если какой-либо пользователь ссылки на изменяемый объект изменяет ее, все другие пользователи этой ссылки видят это изменение. Если это не ожидаемый эффект, может быть сложно уведомить других пользователей, чтобы они ответили правильно. В этих ситуациях защитное копирование всего объекта, а не ссылки, обычно является простым, но дорогостоящим решением. В образец наблюдателя это альтернативный метод обработки изменений изменяемых объектов.

Копирование при записи

Техника, сочетающая в себе преимущества изменчивый и неизменный объектов и поддерживается практически во всем современном оборудовании. копирование при записи (КОРОВА). Используя этот метод, когда пользователь просит систему скопировать объект, вместо этого он просто создает новую ссылку, которая по-прежнему указывает на тот же объект. Как только пользователь пытается изменить объект с помощью определенной ссылки, система создает реальную копию, применяет к ней изменения и устанавливает ссылку для ссылки на новую копию. Остальные пользователи не затронуты, потому что они по-прежнему ссылаются на исходный объект. Следовательно, в COW все пользователи имеют изменяемую версию своих объектов, хотя в случае, если пользователи не изменяют свои объекты, сохраняются преимущества неизменяемых объектов в экономии места и скорости. Копирование при записи популярно в виртуальная память систем, потому что это позволяет им экономить пространство памяти, при этом правильно обрабатывая все, что может делать прикладная программа.

Интернирование

Практика использования ссылок вместо копий одинаковых объектов известна как интернирование. Если используется интернирование, два объекта считаются равными тогда и только тогда, когда их ссылки, обычно представленные как указатели или целые числа, равны. Некоторые языки делают это автоматически: например, Python автоматически стажеры короткие строки. Если алгоритм, реализующий интернирование, гарантированно будет делать это во всех возможных случаях, то сравнение объектов на равенство сводится к сравнению их указателей - существенный выигрыш в скорости в большинстве приложений. (Даже если не гарантируется, что алгоритм будет всеобъемлющим, все же существует возможность быстрый путь улучшение случая, когда объекты равны и используют одну и ту же ссылку.) Интернирование обычно полезно только для неизменяемых объектов.

Безопасность потоков

Неизменяемые объекты могут быть полезны в многопоточных приложениях. Несколько потоков могут работать с данными, представленными неизменяемыми объектами, не беспокоясь о том, что данные изменяются другими потоками. Поэтому неизменяемые объекты считаются более потокобезопасный чем изменяемые объекты.

Нарушение неизменности

Неизменяемость не означает, что объект, хранящийся в компьютере объем памяти не может быть записан. Скорее неизменность - это время компиляции конструкция, которая указывает, что программист может делать через обычный интерфейс объекта, не обязательно то, что он может сделать абсолютно (например, обходя систему типов или нарушая const правильность в C или C ++ ).

Детали для конкретного языка

В Python, Ява и .NET Framework, строки - неизменяемые объекты. И Java, и .NET Framework имеют изменяемые версии строки. В Java это StringBuffer и StringBuilder (изменяемые версии Java Строка), а в .NET это StringBuilder (изменяемая версия .Net Строка). Python 3 имеет изменяемый вариант строки (байтов) с именем bytearray.[4]

Кроме того, все примитивные классы-оболочки в Java неизменны.

Подобные закономерности Неизменяемый интерфейс и Неизменяемая оболочка.

В чистом виде функциональное программирование языках невозможно создавать изменяемые объекты без расширения языка (например, через библиотеку изменяемых ссылок или интерфейс внешней функции ), поэтому все объекты неизменяемы.

Ада

В Ада, любой объект объявляется либо Переменная (т.е. изменяемый; обычно неявное значение по умолчанию) или постоянный (т.е. неизменяемый) через постоянный ключевое слово.

  тип Some_type является новый Целое число; - могло быть что угодно посложнее  Икс: постоянный Some_type:= 1; -- неизменный  у: Some_type; - изменчивый

Параметры подпрограммы неизменяемы в в режим и изменяемый в внутрь и вне режимы.

  процедура Сделай это(а: в Целое число; б: в вне Целое число; c: вне Целое число) является  начинать    - неизменен    б:= б + а;    c:= а;  конец Сделай это;

C #

В C # вы можете обеспечить неизменность полей класса с помощью только чтение утверждение. Установив все поля как неизменяемые, вы получите неизменяемый тип.

класс AnImmutableType{    общественный только чтение двойной _ценить;    общественный AnImmutableType(двойной Икс)     {         _ценить = Икс;     }    общественный AnImmutableType Квадрат()     {         вернуть новый AnImmutableType(_ценить * _ценить);     }}

C ++

В C ++ const-правильно реализация Корзина позволит пользователю объявлять новые экземпляры класса как const (неизменяемый) или изменяемый, по желанию, путем предоставления двух разных версий getItems () метод. (Обратите внимание, что в C ++ нет необходимости - и фактически невозможно - предоставлять специализированный конструктор для const экземпляры.)

класс Корзина { общественный:  Корзина(стандартное::вектор<Предмет> Предметы): Предметы_(стандартное::шаг(Предметы)) {}  стандартное::вектор<Предмет>& Предметы() { вернуть Предметы_; }  const стандартное::вектор<Предмет>& Предметы() const { вернуть Предметы_; }  int ComputeTotalCost() const { / * возврат суммы цен * / } частный:  стандартное::вектор<Предмет> Предметы_;};

Обратите внимание, что если есть поле, которое является указателем или ссылкой на другой объект, тогда все еще может быть возможно изменить объект, на который указывает такой указатель или ссылка в константном методе, без нарушения константной корректности. Можно утверждать, что в таком случае объект на самом деле не является неизменным.

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

класс Корзина { общественный:  Корзина(стандартное::вектор<Предмет> Предметы): Предметы_(стандартное::шаг(Предметы)) {}  const стандартное::вектор<Предмет>& Предметы() const { вернуть Предметы_; }  int ComputeTotalCost() const {    если (Общая стоимость_) {      вернуть *Общая стоимость_;    }    int Общая стоимость = 0;    за (const авто& предмет : Предметы_) {      Общая стоимость += предмет.Расходы();    }    Общая стоимость_ = Общая стоимость;    вернуть Общая стоимость;  } частный:  стандартное::вектор<Предмет> Предметы_;  изменчивый стандартное::необязательный<int> Общая стоимость_;};

D

В D, существует два квалификаторы типа, const и неизменный, для переменных, которые нельзя изменить.[5] В отличие от C ++ const, Java окончательныйи C # только чтение, они транзитивны и рекурсивно применяются ко всему, что доступно через ссылки такой переменной. Разница между const и неизменный к чему они относятся: const является свойством переменной: юридически могут существовать изменяемые ссылки на указанное значение, т.е. значение может фактически изменяться. В отличие, неизменный является свойством упомянутого значения: значение и все, что транзитивно достижимо из него, не может измениться (без нарушения системы типов, что приводит к неопределенное поведение ). Любая ссылка на это значение должна быть отмечена const или неизменный. В основном для любого неквалифицированного типа Т, const (Т) дизъюнктное объединение Т (изменяемый) и неизменяемый (T).

класс C {  / * изменяемый * / Объект mField;    const     Объект cField;    неизменный Объект iField;}

Для изменчивого C объект, его mField можно писать на. Для const (C) объект, mField не может быть изменен, наследует const; iField по-прежнему неизменен, поскольку это более сильная гарантия. Для неизменяемый (C), все поля неизменяемы.

В такой функции:

пустота func(C м, const C c, неизменный C я){ / * внутри фигурных скобок * / }

Внутри подтяжек, c может относиться к тому же объекту как м, поэтому мутации в м может косвенно изменить c также. Также, c может относиться к тому же объекту как я, но поскольку тогда значение неизменяемо, изменений нет. Однако, м и я не может юридически относиться к одному и тому же объекту.

На языке гарантий mutable не имеет никаких гарантий (функция может изменить объект), const является только внешней гарантией, что функция ничего не изменит, и неизменный является двунаправленной гарантией (функция не изменяет значение, и вызывающий не должен его изменять).

Ценности, которые const или неизменный должен быть инициализирован прямым назначением в точке декларация или конструктор.

Потому что const параметры забывают, было ли значение изменяемым или нет, аналогичная конструкция, inout, действует, в некотором смысле, как переменная для информации об изменчивости. Функция const (S) (const (T)) возвращается const (S) типизированные значения для изменяемых, константных и неизменяемых аргументов. Напротив, функция типа функция inout (S) (inout (T)) возвращается S для изменчивого Т аргументы const (S) за const (Т) ценности и неизменяемый (S) за неизменяемый (T) значения.

Приведение неизменяемых значений к изменяемым вызывает неопределенное поведение при изменении, даже если исходное значение происходит из изменяемого источника. Преобразование изменяемых значений в неизменяемые может быть законным, если после этого не останется изменяемых ссылок. «Выражение может быть преобразовано из изменяемого (...) в неизменяемое, если выражение уникально и все выражения, на которые оно транзитивно ссылается, являются уникальными или неизменяемыми».[5] Если компилятор не может доказать уникальность, преобразование может быть выполнено явно, и программист должен убедиться, что не существует изменяемых ссылок.

Тип нить это псевдоним для неизменяемый (символ) [], то есть типизированный фрагмент памяти неизменяемых символов.[6] Создание подстрок дешево, поскольку оно просто копирует и изменяет указатель и поле длины, и безопасно, поскольку базовые данные не могут быть изменены. Объекты типа const (char) [] может относиться к строкам, но также и к изменяемым буферам.

Создание неглубокой копии константного или неизменяемого значения удаляет внешний слой неизменяемости: Копирование неизменяемой строки (неизменяемый (char [])) возвращает строку (неизменяемый (символ) []). Неизменяемый указатель и длина копируются, и копии изменяемы. Указанные данные не были скопированы и сохраняют свой квалификатор, в примере неизменный. Его можно удалить, сделав копию по глубине, например с использованием обман функция.

Ява

Классический пример неизменяемого объекта - это экземпляр Java Строка класс

Строка s = "Азбука";s.toLowerCase();

Метод toLowerCase () не изменяет данные "ABC", которые s содержит. Вместо этого создается новый объект String, которому во время его создания предоставляются данные «abc». Ссылка на этот объект String возвращается toLowerCase () метод. Чтобы сделать строку s содержат данные abc, нужен другой подход:

s = s.toLowerCase();

Теперь строка s ссылается на новый объект String, содержащий «abc». В синтаксисе декларация класса String, который применяет его как неизменяемый; скорее, ни один из методов класса String никогда не влияет на данные, содержащиеся в объекте String, что делает его неизменяемым.

Ключевое слово окончательный (подробная статья ) используется при реализации неизменяемых примитивных типов и объектных ссылок,[7] но он сам по себе не может сами объекты неизменный. См. Примеры ниже:

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

int я = 42; // int - это примитивный типя = 43; // OKокончательный int j = 42;j = 43; // не компилируется. j является окончательным, поэтому его нельзя переназначить

Ссылочные типы нельзя сделать неизменяемыми, просто используя окончательный ключевое слово. окончательный только предотвращает переназначение.

окончательный MyObject м = новый MyObject(); // m имеет ссылочный типм.данные = 100; // OK. Мы можем изменить состояние объекта m (m изменчиво, и final не меняет этого факта)м = новый MyObject(); // не компилируется. m является окончательным, поэтому его нельзя переназначить

Примитивные обертки (Целое число, Длинная, короткий, Двойной, Плавать, Характер, Байт, Булево) также все неизменны. Неизменяемые классы могут быть реализованы, следуя нескольким простым рекомендациям.[8]

Perl

В Perl, можно создать неизменяемый класс с библиотекой Moo, просто объявив все атрибуты только для чтения:

пакет Неизменный;использовать Му;имеет ценить => (    является      => 'ро',   # только чтение    по умолчанию => 'данные', # можно переопределить, указав в конструкторе                       # значение: Immutable-> new (value => 'something else'););1;

Для создания неизменяемого класса обычно требовалось два шага: во-первых, создание аксессоров (автоматически или вручную), предотвращающих изменение атрибутов объекта, и, во-вторых, предотвращение прямого изменения данных экземпляра экземпляров этого класса (обычно это хранилось в хэше). ссылку и может быть заблокирован с помощью функции lock_hash Hash :: Util):

пакет Неизменный;использовать строгий;использовать предупреждения;использовать основание qw (Класс :: Аксессор);# создать средства доступа только для чтения__УПАКОВКА__->mk_ro_accessors(qw (значение));использовать Хэш :: Утилита lock_hash;суб новый {    мой $ класс = сдвиг;    вернуть $ класс если ссылка($ класс);    умереть «Аргументы для нового должны быть парами ключ => значение  n»        пока не (@_ % 2 == 0);    мой % по умолчанию = (        ценить => 'данные',    );    мой $ obj = {        % по умолчанию,        @_,    };    благослови $ obj, $ класс;    # предотвратить изменение данных объекта    lock_hash % $ obj;}1;

Или с помощью написанного вручную аксессуара:

пакет Неизменный;использовать строгий;использовать предупреждения;использовать Хэш :: Утилита lock_hash;суб новый {    мой $ класс = сдвиг;    вернуть $ класс если ссылка($ класс);    умереть «Аргументы для нового должны быть парами ключ => значение  n»        пока не (@_ % 2 == 0);    мой % по умолчанию = (        ценить => 'данные',    );    мой $ obj = {        % по умолчанию,        @_,    };    благослови $ obj, $ класс;    # предотвратить изменение данных объекта    lock_hash % $ obj;}# доступ только для чтениясуб ценить {    мой $ self = сдвиг;    если (мой $ new_value = сдвиг) {        # пытаемся установить новое значение        умереть «Этот объект нельзя изменить  n»;    } еще {        вернуть $ self->{ценить}    }}1;

Python

В Python, некоторые встроенные типы (числа, логические значения, строки, кортежи, замороженные наборы) являются неизменяемыми, но пользовательские классы обычно изменяемы. Чтобы имитировать неизменяемость в классе, можно переопределить установку и удаление атрибута, чтобы вызвать исключения:

класс ImmutablePoint:    "" "Неизменяемый класс с двумя атрибутами 'x' и 'y'." ""    __slots__ = ['Икс', 'y']    def __setattr__(себя, *аргументы):        поднять TypeError(«Невозможно изменить неизменяемый экземпляр».)    __delattr__ = __setattr__    def __в этом__(себя, Икс, у):        # Мы больше не можем использовать self.value = value для хранения данных экземпляра        # поэтому мы должны явно вызвать суперкласс        супер().__setattr__('Икс', Икс)        супер().__setattr__('y', у)

Стандартные помощники библиотеки collection. namedtuple и typing.NamedTuple, доступный начиная с Python 3.6, создает простые неизменяемые классы. Следующий пример примерно эквивалентен приведенному выше, плюс некоторые функции, подобные кортежу:

из набор текста импорт NamedTupleимпорт коллекцииТочка = коллекции.именованный('Точка', ['Икс', 'y'])# следующее создает именованный набор, аналогичный приведенному вышекласс Точка(NamedTuple):    Икс: int    у: int

Представлено в Python 3.7, классы данных позволяют разработчикам имитировать неизменяемость с помощью замороженные экземпляры. Если построен замороженный класс данных, классы данных переопределит __setattr __ () и __delattr __ () поднять FrozenInstanceError если вызывается.

из классы данных импорт класс данных@dataclass(замороженный=Истинный)класс Точка:    Икс: int    у: int

JavaScript

В JavaScript, все примитивные типы (Undefined, Null, Boolean, Number, BigInt, String, Symbol) неизменяемы, но пользовательские объекты обычно изменяемы.

функция сделай что-нибудь(Икс) { / * изменение x здесь меняет оригинал? * / };вар ул = 'строка';вар объект = { ан: 'объект' };сделай что-нибудь(ул);         // строки, числа и типы bool неизменяемы, функция получает копиюсделай что-нибудь(объект);         // объекты передаются по ссылке и изменяются внутри функцииdoAnotherThing(ул, объект); // `str` не изменилась, но` obj` может измениться.

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

вар объект = {};Объект.defineProperty(объект, 'фу', { ценить: 'бар', записываемый: ложный });объект.фу = 'bar2'; // молча игнорируется

Однако описанный выше подход по-прежнему позволяет добавлять новые свойства. В качестве альтернативы можно использовать Object.freeze сделать существующие объекты неизменяемыми.

вар объект = { фу: 'бар' };Объект.заморозить(объект);объект.фу = 'бары'; // не может редактировать свойство, игнорируется автоматическиобъект.foo2 = 'bar2'; // невозможно добавить свойство, игнорируется молча

При реализации ECMA262, JavaScript имеет возможность создавать неизменяемые ссылки, которые нельзя переназначить. Однако, используя const объявление не означает, что значение ссылки только для чтения является неизменным, просто имя не может быть присвоено новому значению.

const ВСЕГДА_ИММУТАБЕЛЬНО = истинный;пытаться {  ВСЕГДА_ИММУТАБЕЛЬНО = ложный;} ловить (ошибаться) {  консоль.бревно(«Невозможно переназначить неизменяемую ссылку».);}const обр = [1, 2, 3];обр.толкать(4);консоль.бревно(обр); // [1, 2, 3, 4]

Использование неизменяемого состояния стало растущей тенденцией в JavaScript с момента появления Реагировать, который поддерживает шаблоны управления состоянием, подобные Flux, такие как Redux.[9]

Ракетка

Ракетка существенно отличается от других Схема реализаций, сделав его основной тип пары ("cons-ячейки") неизменяемым. Вместо этого он предоставляет параллельный изменяемый тип пары через mcons, автомобиль, set-mcar! и т.д. Кроме того, поддерживаются многие неизменяемые типы, например неизменяемые строки и векторы, и они широко используются. Новые структуры по умолчанию неизменяемы, если только поле специально не объявлено изменяемым, или вся структура:

(структура foo1 (Икс у))             ; все поля неизменяемы(структура foo2 (Икс [у #: изменчивый])) ; одно изменяемое поле(структура foo3 (Икс у) #: изменчивый)   ; все поля изменяемы

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

Ржавчина

Ржавчины владение Система позволяет разработчикам объявлять неизменяемые переменные и передавать неизменяемые ссылки. По умолчанию все переменные и ссылки неизменяемы. Изменяемые переменные и ссылки явно создаются с помощью мут ключевое слово.

Постоянные предметы в Rust всегда неизменны.

// постоянные элементы всегда неизменяемыconstВСЕГДА_ИММУТАБЕЛЬНО: bool =истинный;структура Объект{Икс: использовать,у: использовать,}fn основной(){// явно объявляем изменяемую переменнуюпозволятьмутmutable_obj=Объект{Икс: 1,у: 2};mutable_obj.Икс=3;// Ладнопозволятьmutable_ref=&мутmutable_obj;mutable_ref.Икс=1;// Ладнопозволятьimmutable_ref=&mutable_obj;immutable_ref.Икс=3;// ошибка E0594// по умолчанию переменные неизменяемыпозволятьimmutable_obj=Объект{Икс: 4,у: 5};immutable_obj.Икс=6;// ошибка E0596позволятьmutable_ref2=&мутimmutable_obj;// ошибка E0596позволятьimmutable_ref2=&immutable_obj;immutable_ref2.Икс=6;// ошибка E0594}

Scala

В Scala, любая сущность (узко, привязка) может быть определена как изменяемая или неизменяемая: в объявлении можно использовать вал (значение) для неизменяемых сущностей и вар (переменная) для изменяемых. Обратите внимание, что даже несмотря на то, что неизменяемая привязка не может быть переназначена, она по-прежнему может относиться к изменяемому объекту, и по-прежнему можно вызывать методы изменения для этого объекта: привязка неизменен, но лежащий в основе объект может быть изменчивым.

Например, следующий фрагмент кода:

вал maxValue = 100вар текущая стоимость = 1

определяет неизменяемую сущность maxValue (целочисленный тип определяется во время компиляции) и изменяемая сущность с именем текущая стоимость.

По умолчанию классы коллекций, такие как Список и карта неизменяемы, поэтому методы обновления возвращают новый экземпляр, а не изменяют существующий. Хотя это может показаться неэффективным, реализация этих классов и их гарантии неизменности означают, что новый экземпляр может повторно использовать существующие узлы, что, особенно в случае создания копий, очень эффективно.[10][нужен лучший источник ]

Смотрите также

Рекомендации

Эта статья содержит некоторые материалы из Книга шаблонов дизайна Perl

  1. ^ «неизменное прилагательное - Определение, изображения, произношение и примечания к использованию - Оксфордский словарь для продвинутых учащихся на OxfordLearnersDictionaries.com». www.oxfordlearnersdoxaries.com.
  2. ^ а б c Goetz et al. Параллелизм Java на практике. Addison Wesley Professional, 2006, раздел 3.4. Неизменность
  3. ^ Дэвид О'Мира (апрель 2003 г.). «Изменяемые и неизменяемые объекты: убедитесь, что методы нельзя переопределить». Ранчо Ява. Получено 2012-05-14. Предпочтительный способ - сделать класс финальным. Иногда это называют «строгой неизменяемостью». Это не позволяет кому-либо расширять ваш класс и случайно или намеренно сделать его изменяемым.
  4. ^ «Встроенные функции - документация Python v3.0». docs.python.org.
  5. ^ а б D Спецификация языка § 18
  6. ^ Спецификация языка D § 12.16 (Условия множество и ломтик используются взаимозаменяемо.)
  7. ^ «Как создать неизменяемый класс и объект в Java - учебный пример». Javarevisited.blogspot.co.uk. 2013-03-04. Получено 2014-04-14.
  8. ^ «Неизменяемые объекты». javapractices.com. Получено 15 ноября, 2012.
  9. ^ «Неизменяемость в JavaScript: противоположная точка зрения». Desalasworks.
  10. ^ "Scala 2.8 Collections API - конкретные неизменяемые классы коллекций". Scala-lang.org. Получено 2014-04-14.

внешняя ссылка