Когда читаешь умные книги по фнкциональному программированию (в моем случае это была книга по Scala) везде пишут, что immutable это добро. Вроде бы результат налицо: сама собой пропадает проблема с многопоточностью и сайд эффектом к которому может привести mutable. Но также у такого подхода есть свои недостатки (как я понял).
Например есть задача добавить в массив 1000, нет 100000 элементов. True-fp программер скажет что immutable это добро и нам нужно при каждом добавлении создавать новый массив который состоит из элементов старого +1 (что успешно реализовано на уровне ЯП, в двнном случае Scala). Неужели такой подход оправдан с точки зрения ресурсов (памяти в данном случае)? Ведь задача проста, добавлять элементы в массив, на что мы имеем создание 100000 экземпляров массива. Да, я понимаю, что там есть GC который будет убирать за нами, но создание такой достаточно сложной структуры данных как массив (имеется в виду List) будет занимать достаточно большое время.
Что на это скажете?
Помимо всего прочего, на мой взгляд - вещи, которые меняются - это всегда дополнительная сложность и источник дефектов. Таким образом immutable позволяет уменьшить вышеуказанные риски, порой ценою ресурсов.
Допустим есть класс, в котором есть какое-то поле, которое устанавливается при создании экземпляра этого класса, и читая код - мы можем быть 100% уверенны, что это поле сохранит своё значение при любых условиях для данного экземляра и нам не нужно будет выискивать чтобы ещё с ним могло произойти. Опять таки, можно не заморачиваться с геттерами создал публичную immutable переменную - и данные сразу защищены от записи извне.
Есть immutable List. Этот List заточен на добавление и удаление элементов в начале списка – head. И если вы делаете map или filter списка – новый список формируется в том же "оптимальном" порядке.
В таком случае никакого перерасхода памяти и нагрузки на GC по сравнению с Java LinkedList нет: при добавлении элемента создается НОВЫЙ объект List со ссылкой на новый элемент (head) и ссылкой на прежний список (tail). Старые листы в деле. Каждый новый лист – объект из всего двух референсов.
Неужели такой подход оправдан с точки зрения ресурсов (памяти в данном случае)?
В функциональных языках, в том числе в Scala используются т.н. persistent data structures. В памяти хранятся ссылки на предыдущие состояния структуры данных и изменения. Это имеет смысл в сочетании с упомянутой вами сборкой мусора. Разумеется можно просто копировать всё, но на деле так никто не делает. Поскольку в ФП очень много используются структуры типа списков и деревьев, для них это легко реализовать эффективно.
Рекомендую почитать (англ.) википедию по ссылке выше или вот эту вики на русском.