Różnica między niezmienną a stałą

28

Często widziałem warunki immutablei constużywałem zamiennie. Jednak z mojego (niewielkiego) doświadczenia wynika, że ​​te dwie rzeczy bardzo różnią się między sobą „umową”, którą zawierają w kodzie:

Immutable sprawia, że ​​kontrakt, którego ten obiekt się nie zmieni (np. Krotki Python, łańcuchy Java).

Const zawiera umowę, że w zakresie tej zmiennej nie będzie modyfikowana (nie obiecuje żadnych innych wątków, które mogłyby zrobić z obiektem wskazanym w tym okresie, np. Słowo kluczowe C / C ++).

Oczywiście, te dwa nie są równoważne, chyba że język jest jednowątkowy (PHP) lub ma liniowy lub jednoznaczny system pisania (Clean, Mercury, ATS).

Po pierwsze, czy moje rozumienie tych dwóch pojęć jest prawidłowe?

Po drugie, jeśli istnieje różnica, dlaczego są one prawie wyłącznie używane zamiennie?

K.Steff
źródło
1
constnie istnieje w każdym języku, a zmienność i niezmienność nie istnieje w każdym języku, więc sprawienie, by ten język był agonistyczny, nie ma zastosowania. Jest on specyficzny dla języka tylko wtedy, gdy te pojęcia mają zastosowanie.
2
Powiązana, zalecana lektura: Rodzaje niezmienności (kilka przykładów języka C #, ale w dużej mierze niezależne od języka). Ktoś wręcza Ericowi Lippertowi medal.

Odpowiedzi:

14

Porozmawiam z C ++, gdzie ta różnica jest najbardziej istotna.

Jak słusznie zauważysz, niezmienny oznacza, że ​​obiekt nie może się w ogóle zmienić po jego utworzeniu. To tworzenie może oczywiście nastąpić w czasie wykonywania, tzn. constObiekt niekoniecznie musi być stałą czasową kompilacji. W C ++ obiekt jest niezmienny, jeśli spełnione są (1) i (2) lub (3):

  1. Nie ma zadeklarowanych członków mutablezmutowanych przez constfunkcje członka

  2. Zostało zadeklarowane const

  3. constfunkcje członków nie służą const_castdo usuwania constkwalifikacji w celu mutowania jakichkolwiek członków

Można jednak również rozważyć modyfikatory dostępu: jeśli operacja mutuje instancję wewnętrznie, ale nie ma wpływu na stan instancji obserwowalny przez jej publiczny interfejs, obiekt jest „logicznie niezmienny”.

Tak więc C ++ zapewnia narzędzia niezbędne do tworzenia niezmiennych obiektów, ale podobnie jak większość wszystkiego w C ++, narzędzia są tylko w minimalnym stopniu wystarczające i wymagają staranności, aby móc ich używać. Stan instancji niekoniecznie ogranicza się do zmiennych składowych instancji - ponieważ C ++ nie zapewnia sposobu wymuszania przejrzystości referencyjnej, może również obejmować stan globalny lub klasowy.

constma także inną funkcję w C ++: kwalifikowanie referencji i wskaźników. constOdniesienia może odnosić się do nie- constprzedmiotu. Używanie const_castdo mutowania obiektu za pomocą constodwołania jest legalne (choć nie jest to generalnie konieczne lub wskazane) , i tylko wtedy , gdy obiekt ten jest zadeklarowany jako inny niż const:

int        i = 4;         // Non-const object.
const int* p = &i;        // const pointer.

*const_cast<int*>(p) = 5; // Legal.

I oczywiście mutowanie constobiektu jest niezdefiniowane :

const int  i = 4;         // const object.
const int* p = &i;        // const pointer.

*const_cast<int*>(p) = 5; // Illegal.
Jon Purdy
źródło
19

Mówiąc w języku Java, gdzie słowo kluczowe „final” oznacza „const”, rozważ:

final Person someone = new Person();

Oznacza to, someoneże NIGDY nie może odnosić się do innego obiektu Osoby. Ale nadal możesz zmienić dane osoby poleconej. Na przykładsomeone.setMonthlySalary(10000);

Ale jeśli someonebyłby to obiekt „niezmienny”, spełniony byłby jeden z następujących warunków: (a) Nie miałbyś metody o nazwie setMonthlySalary (b) Wywołanie setMonthlySalary zawsze rzucałoby wyjątek taki jakUnsupportedOperationException

rationalrevolt
źródło
10

Niezmienne obiekty to takie, które nie zmieniają stanu po jego utworzeniu. Na przykład;

string prefix = "Pre";
string postfix = "Post";
string myComplexStr = prefix + postfix;

W tym przykładzie obiekt myComplexStr jest niezmienny, ale nie jest stały, ponieważ jego wartość jest obliczana. I jest niezmienny, ponieważ jest łańcuchem i ma właściwość długości statycznej i nie może się zmienić.

Obiekty Const są zwykle używane do identyfikacji niektórych rzeczywistych stałych, których wartości są znane przed kompilacją, takich jak Pi, „USA”, „StackOverflow.com”, numery portów i tak dalej.

Z tej perspektywy Const różni się od niezmiennych obiektów, ponieważ ich wartości nie są obliczane przez program.

Ale jeśli mówisz o słowie kluczowym „const” w C ++, możesz powiedzieć, że „const” służy do tworzenia niezmiennych obiektów.

Mert Akcakaya
źródło
1
const w C ++ nie tworzy niezmiennych obiektów, to tylko poziom dostępu.
Klaim
Czy potrafisz wyjaśnić, dlaczego „const double pi = 3.14” nie jest niezmienne?
Mert Akcakaya
To zależy od tego, gdzie to jest. Powiedzmy, że tak: „double * p_pi = const_cast <double *> (& pi); * p_pi = 42;” na przykład. Jeśli więc pi znajduje się w globalnej przestrzeni lub przestrzeni nazw, pojawia się błąd segmentacji, ale moim zdaniem jest to niezdefiniowane zachowanie, a nie konkretny błąd. Jeśli pi jest członkiem dowolnego obiektu dostępnego w czasie wykonywania, który nie jest statyczny, otrzymuję pi == 42. Widzisz, nawet użycie zmiennego jest dostępne, ponieważ const w C ++ dotyczy poziomu dostępu, semantycznego, a nie niezmienności danych, że jest prawie niemożliwe do osiągnięcia w C ++. Możesz to tylko „zasymulować”. const nie jest niezmienny.
Klaim
1
@Klaim Mutowanie consttego typu jest niezdefiniowanym zachowaniem bez względu na to, gdzie jest przydzielone, IIRC. Nieokreślone zachowanie jest gorsze niż jakikolwiek konkretny błąd, który może się zdarzyć. Oznacza to, że nie używasz już C ++ - C ++ nie zapewnia możliwości zmiany constwartości (z wyjątkiem mutableczłonków, ale nie o to ci chodzi), więc jeśli chodzi o C ++, nie możesz tego zrobić. To, co konkretne implementacje pozwalają, to zupełnie inna sprawa (i założę się, że jeśli skompilujesz z optymalizacjami, wyczyn, który wykonałeś, nie wpłynie na późniejsze wyrażenia, piponieważ został zastąpiony).
„const w C ++ nie tworzy niezmiennych obiektów” jest nadal błędne, ponieważ nadal tworzy stałe globalne, jak napisałeś we własnej odpowiedzi. Słowo kluczowe jest oczywiście semantyczne na pewnym poziomie, w przeciwnym razie zawsze możesz po prostu ręcznie zmienić napięcie komórki pamięci i zmienić wartość niezmiennego obiektu, jeśli tak bardzo chcesz użyć niezdefiniowanych zachowań.
Mert Akcakaya
8

Po pierwsze, czy moje rozumienie tych dwóch pojęć jest prawidłowe?

Tak, ale twoje drugie pytanie pokazuje, że nie rozumiesz tych różnic.

Po drugie, jeśli istnieje różnica, dlaczego są one prawie wyłącznie używane zamiennie?

constw C ++ jest używany tylko dla poziomu dostępu (oznacza „tylko do odczytu”) , a nie dla niezmienności. Oznacza to, że sam dostęp jest całkowicie oddzielony od danych. Na przykład możesz manipulować niektórymi danymi, a następnie ujawnić je za pomocą stałego odwołania. Dostęp jest tylko do odczytu, ale same dane, ponieważ cały datam jest zmienny.

const tylko ograniczenia dostępu gwarantowane, podczas gdy niezmienność (jak na przykład w D) nie implikuje naprawdę żadnego sposobu zmiany danych na dowolnym etapie życia obiektu .

Teraz możesz symulować niezmienność w C ++, upewniając się, że dostęp do niektórych danych nie jest możliwy w żaden inny sposób niż const, i upewnij się, że jest on inicjowany, a następnie nie dotykany. Ale to nie jest silna gwarancja, ponieważ języki takie jak D dają ci, gdy oznaczysz swoje dane jako niezmienne. Język upewnia się, że nie można w ogóle wykonać żadnej operacji modyfikującej te dane, podczas gdy w C ++ nadal jesteś w stanie potencjalnie zmienić dane poprzez rzutowanie i modyfikowanie, jeśli jest to naprawdę konieczne.

Ostatecznie nie jest wcale taki sam, ponieważ nie oferuje takich samych gwarancji.

Klaim
źródło
3

Mówiąc o JavaScript, słowach kluczowych constiObject.freeze

constdotyczy powiązańvariables . Tworzy niezmienne wiązanie, nie można mu przypisać nowej wartości.

Object.freezedziała na wartościach obiektów. Sprawia, że ​​obiekt jest niezmienny . Mianowicie nie można zmienić jego właściwości.

zangw
źródło
0

W C ++ są takie same. Chociaż możesz zmienić constobiekt, jeśli masz jego lokalizację w pamięci i pozwolenie systemu operacyjnego na zapis do tej pamięci.

Martin Beckett
źródło
1
W rzeczywistości jest to argument przeciwko tym, że są tacy sami: C ++ po prostu nie ma niezmiennego słowa kluczowego ani obsługi języka. Zakładam też, że programista używa języka w rozsądny sposób: w przeciwnym razie const również nie ma absolutnie żadnej wartości.
K.Steff
1
@ K.Steff - być może lepiej powiedzieć, że nie ma żadnej dodatkowej niezmienności w C ++ poza zapewnioną przez const
Martin Beckett
Absolutnie precyzyjne :)
K.Steff
W C ++ wcale nie są takie same. const jest poziomem dostępu „tylko do odczytu”, nie oznacza to, że dane są niezmienne. Przez większość czasu możesz go ominąć w C ++.
Klaim
0

W językach C, C ++ i pokrewnych istnieje również różnica między obiektem będącym stałym a odniesieniem lub wskaźnikiem do obiektu będącego stałym odniesieniem.

Jeśli spróbujesz zmodyfikować stały obiekt, otrzymasz niezdefiniowane zachowanie. (Możesz spróbować zmodyfikować stały obiekt, na przykład biorąc jego adres, rzutując adres na wskaźnik nie będący const, a następnie używając tego wskaźnika non-const do modyfikacji obiektu).

Z drugiej strony stały wskaźnik lub odniesienie informuje kompilator, że nie można użyć tego wskaźnika lub odniesienia do modyfikacji obiektu. Możesz rzucić wskaźnik lub odwołanie i spróbować zmodyfikować obiekt. Jeśli sam obiekt był stały, zdarzałyby się złe rzeczy. Jeśli obiekt nie był faktycznie stały, zmieni się. Może to oczywiście mylić użytkowników twojego kodu i być może powodować błędy.

W C, jeśli użyjesz literału łańcuchowego, takiego jak „Hello”, pięć znaków i końcowe bajty zerowe są w rzeczywistości stałe, ale otrzymujesz wskaźnik non-const. Bardzo zły pomysł, aby użyć tego nie-stałego wskaźnika do zmiany obiektu.

W C możesz mieć wskaźnik „const ograniczać”. Oznacza to, że wskazany obiekt jest tymczasowo stały. Jeśli obiekt zostanie zmodyfikowany w jakikolwiek sposób, gdy wskaźnik „const ograniczy” znajduje się w zasięgu, zachowanie jest niezdefiniowane. Jest to silniejsze niż wskaźnik const, który tylko uniemożliwia zmianę obiektu za pomocą tego wskaźnika.

gnasher729
źródło