Niemutowalne struktury danych są esencją programowania funkcyjnego. Za Wikipedią:
In computer science, functional programming is a programming paradigm—a style of building the structure and elements of computer programs—that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data. It is a declarative programming paradigm, which means programming is done with expressions[1] or declarations[2] instead of statements.
Podzbiorem stylu funkcyjnego jest programowanie czysto funkcyjne, gdzie cały program musi być czysto funkcyjny: https://en.wikipedia.org/wiki/Purely_functional_programming
A purely functional language is a language which only admits purely functional programming. Purely functional programs can however be written in languages which are not purely functional.
Jeżeli w jakiejś metodzie czy funkcji unikniesz mutowalności (w tym polegania na mutowalnym stanie z zewnątrz) to ta funkcja jest napisana w stylu funkcyjnym. Ilość takich metod czy funkcji możesz zwiększać (dopóki uznasz to za stosowne) zastępując nimi imperatywne poprzedniki i wtedy mieszasz styl funkcyjny z imperatywnym. Mieszając FP z OOP najwięcej sensu jest gdy cały obiekt jest napisany w stylu funkcyjnym, a nie tylko części, bo
- w stylu imperatywnym i tak są funkcje czy metody nie modyfikujące stanu,
- łatwiej zapamiętać, że cały obiekt jest funkcyjny, a nie konkretne jego metody - jeśli wrzucę obiekt z mutatorami gdzieś dalej to nie jestem pewien czy nie zostanie zmieniony - obiekt bez mutatorów na pewno nie zostanie
Z funkcyjnością jest związana jeszcze jedna sprawa - otóż można mieć funkcję, która z zewnątrz zachowuje się jakby była czysto funkcyjna, ale w środku używa mutowalnych struktur danych. Dla przykładu:
def sum(ints: Seq[Int]): Int = {
var result = 0
ints.foreach(result += _)
result
}
Mimo iż użyliśmy zmiennej to metoda dalej nie zależy od zewnętrznego mutowalnego stanu, nie ma efektów ubocznych widocznych z zewnątrz i spełniony jest warunek, że dla tego samego wejścia zawsze dostaniemy to samo wyjście. Dostajemy więc szereg zalet związanych z funkcyjnym stylem programowania, ale dodatkowo zoptymalizowaliśmy sobie wydajność używając lokalnej zmiennej.
Niemutowalne kolekcje w Scali zawierają szereg takich optymalizacji opartych o nieobserwowalną z zewnętrz lokalną mutowalność.
Więcej dyskusji: https://softwareengineering.stackexchange.com/q/196112
No i jeszcze jedna sprawa, bo nie jestem pewien czy dokładnie zrozumiałem argument. Oczywiście da się używać niemutowalnych obiektów nie myśląc o funkcyjności, ale chcąc je szerzej używać szybko wejdzie się w schematy znane z podejścia funkcyjnego. No chyba, że nasza niemutowalność oznacza rzucanie wyjątku przy odpalaniu mutatora.