Pamiętaj, że jeśli to Ci odpowiada, ale w językach funkcjonalnych, takich jak Standard ML, domyślnie wszystko jest niezmienne. Mutacja jest wspierana przez ogólny reftyp erence. Więc intzmienna jest niezmienna, a ref intzmienna jest zmienny pojemnik na ints. Zasadniczo zmienne są rzeczywistymi zmiennymi w sensie matematycznym (nieznana, ale stała wartość), a refs są „zmiennymi” w sensie programowania imperatywnego - komórką pamięci, z której można zapisywać i odczytywać. (Lubię nazywać je przypisywalnymi ).
Myślę, że problem constjest dwojaki. Po pierwsze, C ++ nie ma funkcji wyrzucania elementów bezużytecznych, co jest konieczne, aby mieć nietrywialne trwałe struktury danych . const musi być głęboki, aby mieć jakikolwiek sens, jednak posiadanie w pełni niezmiennych wartości w C ++ jest niepraktyczne.
Po drugie, w C ++ musisz się zdecydować, consta nie zrezygnować. Ale kiedy zapomnisz o constczymś, a później to naprawisz, skończysz w sytuacji „zatruć const”, o której mowa w odpowiedzi @ RobY, gdzie constzmiana będzie kaskadowo w całym kodzie. Gdyby constbyło to ustawienie domyślne, nie zobaczyłbyś, że aplikujesz z constmocą wsteczną. Dodatkowo konieczność dodawania constwszędzie powoduje znaczny szum w kodzie.
Podejrzewam, że późniejsze języki głównego nurtu (np. Java) były silnie ukształtowane przez sukces i sposób myślenia C i C ++. W tym przypadku nawet w przypadku wyrzucania elementów bezużytecznych większość interfejsów API do zbierania języków zakłada zmienne struktury danych. Fakt, że wszystko jest zmienne i niezmienność jest postrzegany jako przypadek narożny, mówi wiele o imperatywnym sposobie myślenia za popularnymi językami.
EDYCJA : Po przemyśleniu komentarza Greenoldmana zrozumiałem, że constnie chodzi bezpośrednio o niezmienność danych; constkoduje w typie metody, czy ma ona skutki uboczne dla instancji.
Możliwe jest użycie mutacji, aby osiągnąć referencyjnie przejrzyste zachowanie. Załóżmy, że masz funkcję, która wywoływana sukcesywnie zwraca różne wartości - na przykład funkcję, która odczytuje pojedynczy znak stdin. Możemy użyć pamięci podręcznej / zapamiętać wyniki tej funkcji, aby uzyskać referencyjnie przejrzysty strumień wartości. Strumień byłby połączoną listą, której węzły wywołują funkcję przy pierwszej próbie odzyskania ich wartości, ale następnie buforują wynik. Więc jeśli stdinconstains Hello, world!, po raz pierwszy spróbować pobrać wartość pierwszego węzła, to będzie czytać jedną chari powrotu H. Następnie będzie nadal wracał Hbez dalszych wezwań do przeczytania char. Podobnie drugi węzeł odczytałby charzstdinprzy pierwszej próbie odzyskania jego wartości, tym razem zwracamy ei buforujemy ten wynik.
Interesującą rzeczą jest to, że zamieniłeś proces z natury stanowy w obiekt, który na pozór jest bezpaństwowy. Aby to osiągnąć, konieczna była jednak mutacja stanu wewnętrznego obiektu (poprzez buforowanie wyników) - mutacja była łagodnym efektem . Nie da się uczynić naszego, CharStream constnawet jeśli strumień zachowuje się jak niezmienna wartość. Teraz wyobraź sobie, że istnieje Streaminterfejs z constmetodami i oczekują tego wszystkie twoje funkcje const Streams. Twój CharStreamnie może implementować interfejs!
( EDYCJA 2: Najwyraźniej istnieje słowo kluczowe C ++ mutable, które pozwala nam oszukiwać i tworzyćCharStream const . Jednak ta luka niszczy constgwarancje - teraz naprawdę nie możesz być pewien, że coś nie zmutuje za pomocą swoich constmetod. Przypuszczam, że to nie tak źle, ponieważ musisz wyraźnie poprosić o lukę, ale nadal całkowicie polegasz na systemie honoru).
Po drugie, załóżmy, że masz funkcje wyższego rzędu - możesz przekazać funkcje jako argumenty do innych funkcji. constness jest częścią sygnatury funkcji, więc nie można przekazywać constniefunkcji jako argumentów funkcji, które oczekują constfunkcji. Ślepe egzekwowanie consttutaj doprowadziłoby do utraty ogólności.
Wreszcie, manipulowanie constobiektem nie gwarantuje, że nie mutuje on jakiegoś zewnętrznego (statycznego lub globalnego) stanu za twoimi plecami, więc constgwarancje nie są tak silne, jak się początkowo wydają.
Nie jest dla mnie jasne, czy kodowanie obecności lub braku efektów ubocznych w systemie typów jest ogólnie dobrą rzeczą.