Niezmienne obiekty a niezmienne kolekcje
Jednym z lepszych punktów w debacie na temat obiektów zmiennych i niezmiennych jest możliwość rozszerzenia pojęcia niezmienności na kolekcje. Niezmienny obiekt to obiekt, który często reprezentuje pojedynczą logiczną strukturę danych (na przykład niezmienny ciąg znaków). Gdy masz odwołanie do niezmiennego obiektu, zawartość obiektu nie ulegnie zmianie.
Niezmienna kolekcja to kolekcja, która nigdy się nie zmienia.
Kiedy wykonuję operację na mutowalnej kolekcji, zmieniam kolekcję w miejscu, a wszystkie jednostki, które mają odwołania do kolekcji, zobaczą zmianę.
Kiedy wykonuję operację na niezmiennej kolekcji, odwołanie jest zwracane do nowej kolekcji odzwierciedlającej zmianę. Wszystkie jednostki, które mają odniesienia do poprzednich wersji kolekcji, nie zobaczą zmiany.
Sprytne implementacje niekoniecznie muszą kopiować (klonować) całą kolekcję, aby zapewnić tę niezmienność. Najprostszym przykładem jest stos zaimplementowany jako pojedynczo połączona lista i operacje push / pop. Możesz ponownie wykorzystać wszystkie węzły z poprzedniej kolekcji w nowej kolekcji, dodając tylko jeden węzeł do wypychania i nie klonując żadnych węzłów do wyskakiwania. Z drugiej strony operacja push_tail na pojedynczo połączonej liście nie jest tak prosta ani wydajna.
Niezmienne a zmienne zmienne / odwołania
Niektóre języki funkcjonalne przyjmują koncepcję niezmienności do samych odniesień do obiektów, zezwalając tylko na przypisanie pojedynczego odniesienia.
- W Erlang jest to prawdą dla wszystkich „zmiennych”. Obiekty mogę przypisać do odniesienia tylko raz. Gdybym miał operować na kolekcji, nie byłbym w stanie ponownie przypisać nowej kolekcji do starego odniesienia (nazwa zmiennej).
- Scala wbudowuje to również w język, a wszystkie odniesienia są zadeklarowane za pomocą var lub val , przy czym vals są tylko pojedynczym przypisaniem i promują styl funkcjonalny, ale vars pozwalają na strukturę programu podobną do C lub Javy.
- Wymagana jest deklaracja var / val, podczas gdy wiele tradycyjnych języków używa opcjonalnych modyfikatorów, takich jak final w java i const w C.
Łatwość tworzenia a wydajność
Niemal zawsze powodem używania niezmiennego obiektu jest promowanie wolnego od efektów ubocznych programowania i prostego rozumowania kodu (szczególnie w środowisku wysoce współbieżnym / równoległym). Nie musisz się martwić, że dane źródłowe zostaną zmienione przez inną jednostkę, jeśli obiekt jest niezmienny.
Główną wadą jest wydajność. Oto opis prostego testu, który przeprowadziłem w Javie, porównując niektóre niezmienne i zmienne obiekty w problemie z zabawkami.
Problemy z wydajnością są dyskusyjne w wielu aplikacjach, ale nie we wszystkich, dlatego wiele dużych pakietów numerycznych, takich jak klasa Numpy Array w Pythonie, pozwala na aktualizacje w miejscu dużych tablic. Byłoby to ważne dla obszarów zastosowań, które wykorzystują duże operacje na macierzach i wektorach. Te duże, równoległe do danych i wymagające dużej mocy obliczeniowej problemy osiągają ogromne przyspieszenie dzięki działaniu w miejscu.
string
jest niezmienna, przynajmniej w .NET, i myślę, że w wielu innych współczesnych językach.