Czytam Coders at Work , a w nim dużo mówi się o niezmiennikach. O ile rozumiem, niezmiennik jest warunkiem, który utrzymuje się zarówno przed, jak i po wyrażeniu. Przydają się między innymi do udowodnienia, że pętla jest poprawna, jeśli dobrze pamiętam mój kurs logiki.
Czy mój opis jest poprawny, czy coś przeoczyłem? Czy używałeś ich kiedyś w swoim programie? A jeśli tak, to na czym skorzystali?
invariants
gablin
źródło
źródło
Odpowiedzi:
W OOP niezmiennikiem jest zestaw twierdzeń, które muszą zawsze być prawdziwe przez cały czas istnienia obiektu, aby program był ważny. Powinien on obowiązywać od końca konstruktora do początku destruktora, ilekroć obiekt nie wykonuje obecnie metody zmieniającej jego stan.
Przykładem niezmiennika może być to, że dokładnie jedna z dwóch zmiennych składowych powinna mieć wartość NULL. Lub, jeśli jedna ma określoną wartość, to zestaw dozwolonych wartości dla drugiej jest taki czy inny ...
Czasami używam funkcji członka obiektu, aby sprawdzić, czy niezmiennik ma. Jeśli tak nie jest, podnoszony jest aser. Metoda jest wywoływana na początku i na końcu każdej metody zmieniającej obiekt (w C ++ jest to tylko jedna linia ...)
źródło
Cóż, rzeczy, które widzę w tym wątku, są świetne, ale mam definicję „niezmiennika”, który był dla mnie niezwykle pomocny w pracy.
Ta definicja jest pomocna, ponieważ dzieli warunki na dwie grupy: te, którym można zaufać kompilatorowi, oraz te, które należy udokumentować, omówić, skomentować lub w inny sposób przekazać współautorom, aby mogli wchodzić w interakcje z bazą kodu bez wprowadzania błędów .
Również ta definicja jest pomocna, ponieważ pozwala na zastosowanie uogólnienia „Niezmienniki są złe”.
Na przykład dźwignia zmiany biegów w samochodzie z manualną skrzynią biegów została zaprojektowana tak, aby uniknąć niezmiennika. Gdybym chciał, mógłbym zbudować skrzynię biegów z jedną dźwignią dla każdego biegu. Ta dźwignia może być do przodu („załączona”) lub do tyłu („odłączona”). W takim systemie stworzyłem „niezmiennik”, który można udokumentować jako taki:
I tak można winić zepsute transmisje za niechlujną jazdę. Nowoczesne samochody używają jednak jednego drążka, który obraca się między biegami. Jest zaprojektowany w taki sposób, że w nowoczesnym samochodzie z drążkiem zmiany biegów nie można włączyć dwóch biegów jednocześnie.
W ten sposób moglibyśmy powiedzieć, że skrzynia biegów została zaprojektowana do „usunięcia niezmiennika”, ponieważ nie pozwala ona na mechaniczną konfigurację w sposób naruszający regułę logiczną.
Każdy niezmiennik tego rodzaju, który usuwasz z kodu, stanowi ulepszenie, ponieważ zmniejsza obciążenie poznawcze związane z jego obsługą.
źródło
Niezmiennik (w zdrowym znaczeniu) oznacza pewne warunki, które muszą być spełnione w pewnym momencie lub nawet zawsze podczas działania programu. np. PreConditions i PostConditions mogą być wykorzystane do zapewnienia pewnych warunków, które muszą być spełnione, gdy funkcja jest wywoływana i gdy zwraca. Niezmienniki obiektu mogą służyć do stwierdzenia, że obiekt musi mieć prawidłowy stan przez cały czas jego istnienia. Jest to zasada „na podstawie umowy”.
Nieformalnie użyłem niezmienników, używając czeków w kodzie. Ale ostatnio bawię się biblioteką kontraktów kodowych dla .Net, która bezpośrednio obsługuje niezmienniki.
źródło
Na podstawie następującego cytatu z Coders At Work ...
... Chyba „niezmienny” = „warunek, który chcesz utrzymać, aby zapewnić pożądany efekt”.
Wydaje się, że niezmiennik ma dwa zmysły, które różnią się subtelnie:
Więc 1 jest jak twierdzenie; 2 jest jak narzędzie do sprawdzania poprawności, wydajności lub innych właściwości - tak myślę. Zobacz artykuł z Wikipedii na przykład 2 (potwierdzający poprawność rozwiązania zagadki MU).
Właściwie trzecie poczucie niezmiennika to:
.3 Co program (lub moduł lub funkcja) ma zrobić; innymi słowy, jego cel.
Z tego samego wywiadu Coders At Work:
źródło
Niezmiennik jest jak reguła lub założenie, które może być użyte do dyktowania logiki twojego programu.
Załóżmy na przykład, że masz aplikację, która śledzi konta użytkowników. Załóżmy również, że użytkownik może mieć wiele kont, ale z jakiegokolwiek powodu musisz rozróżnić konto główne użytkownika i konto „aliasowe”.
Może to być rekord DB lub coś innego, ale na razie załóżmy, że każde konto użytkownika jest reprezentowane przez obiekt klasy.
klasa userAccount {private char * pUserName; prywatny char * pParentAccountUserName;
...}
Niezmiennikiem może być założenie, że jeśli pParentAccountUserName ma wartość NULL lub jest puste, to ten obiekt jest kontem nadrzędnym. Możesz użyć tego niezmiennika do rozróżnienia różnych typów kont. Prawdopodobnie istnieją lepsze metody rozróżniania różnych typów kont użytkowników, więc pamiętaj, że to tylko przykład pokazujący, w jaki sposób można użyć niezmiennika.
źródło
Pochodząc z fizyki, w fizyce mamy niezmienniki, które są zasadniczo wielkościami, które nie zmieniają się podczas całego obliczenia / symulacji. Na przykład w fizyce dla układu zamkniętego zachowana jest całkowita energia. Lub ponownie w fizyce, jeśli zderzą się dwie cząstki, powstałe fragmenty muszą zawierać dokładnie energię, z której zaczęły, i dokładnie ten sam pęd (wielkość wektorową). Zwykle nie ma wystarczającej liczby niezmienników, aby całkowicie określić wynik. Na przykład w zderzeniu dwuczęściowym mamy cztery niezmienniki, trzy składowe pędu i składnik energetyczny, ale układ ma sześć stopni swobody (sześć liczb opisujących jego stan). Niezmienniki powinny być zachowane w ramach błędu zaokrąglania, ale ich zachowanie nie dowodzi, że rozwiązanie jest poprawne.
Zazwyczaj rzeczy te są ważne jako kontrole poczytalności, ale same w sobie nie mogą udowodnić poprawności.
źródło