Czym dokładnie jest zasada „jak gdyby”?

89

Jak mówi tytuł,

Czym dokładnie jest zasada „jak gdyby”?

Typowa odpowiedź, jaką można uzyskać, to:

Reguła zezwalająca na wszelkie transformacje kodu, które nie zmieniają obserwowalnego zachowania programu

Od czasu do czasu otrzymujemy zachowania z pewnych implementacji, które są przypisane tej regule. Wiele razy źle. Na czym więc dokładnie polega ta zasada. Norma nie wspomina wyraźnie o tej zasadzie jako sekcji lub akapicie, więc co dokładnie obejmuje zakres tej zasady? Wydaje mi się, że jest to szara strefa, której norma nie definiuje szczegółowo. Czy ktoś może rozwinąć szczegóły, powołując się na odniesienia z normy?

Uwaga: oznaczając to jako C i C ++, ponieważ ma to znaczenie dla obu języków.

Alok Save
źródło
2
Odnosi się do abstrakcyjnej maszyny.
Alexey Frunze
Oznaczanie tego zarówno jako C, jak i C ++, ponieważ ma znaczenie dla obu języków ”. Ma znaczenie w każdym języku.
curiousguy
@AlexeyFrunze " Odnosi się do abstrakcyjnej maszyny " Odnosi się do stanu "abstrakcyjnej maszyny" będącej narzędziem, a nie celem, i nieistotnym z punktu widzenia dostosowania, ponieważ jest "abstrakcyjna", czyli nierealnym narzędziem specyfikacji.
curiousguy

Odpowiedzi:

98

Jaka jest zasada „ jak gdyby ”?

Reguła „ as-if ” zasadniczo definiuje, jakie transformacje implementacja może wykonać na legalnym programie w C ++. Krótko mówiąc, wszystkie przekształcenia, które nie wpływają na „ obserwowalne zachowanie ” programu (dokładna definicja znajduje się poniżej).

Celem jest zapewnienie implementacjom swobody wykonywania optymalizacji, o ile zachowanie programu pozostaje zgodne z semantyką określoną w standardzie C ++ w odniesieniu do maszyny abstrakcyjnej.


Gdzie norma wprowadza tę zasadę?

Standard C ++ 11 wprowadza zasadę „ as-if ” w paragrafie 1.9 / 1:

Opisy semantyczne w niniejszej Normie Międzynarodowej definiują sparametryzowaną niedeterministyczną maszynę abstrakcyjną. Niniejsza Norma Międzynarodowa nie nakłada żadnych wymagań dotyczących struktury wdrożeń zgodnych. W szczególności nie muszą kopiować ani naśladować struktury abstrakcyjnej maszyny. Raczej zgodne implementacje są wymagane do emulacji (tylko) obserwowalnego zachowania abstrakcyjnej maszyny, jak wyjaśniono poniżej.

Ponadto przypis wyjaśniający dodaje:

To postanowienie jest czasami nazywane zasadą „jak gdyby” , ponieważ implementacja może zignorować jakiekolwiek wymagania niniejszej Normy Międzynarodowej, o ile wynik jest taki, jakby wymaganie było przestrzegane, o ile można to ustalić na podstawie obserwowalnego zachowania programu. Na przykład rzeczywista implementacja nie musi oceniać części wyrażenia, jeśli może wywnioskować, że jego wartość nie jest używana i że nie powstają żadne skutki uboczne wpływające na obserwowalne zachowanie programu.


Co dokładnie nakazuje reguła?

Pkt 1.9 / 5 dalej określa:

Zgodna implementacja wykonująca dobrze uformowany program będzie dawać takie samo obserwowalne zachowanie, jak jedno z możliwych wykonań odpowiedniej instancji maszyny abstrakcyjnej z tym samym programem i tymi samymi danymi wejściowymi . Jednakże, jeśli jakiekolwiek takie wykonanie zawiera niezdefiniowaną operację, niniejsza Norma Międzynarodowa nie nakłada żadnych wymagań na implementację wykonującą ten program z tym wejściem (nawet w odniesieniu do operacji poprzedzających pierwszą niezdefiniowaną operację).

Warto podkreślić, że ograniczenie to ma zastosowanie tylko przy „wykonywaniu dobrze sformułowanego programu” , a możliwe wyniki wykonania programu, który zawiera niezdefiniowane zachowanie, są nieograniczone. Jest to również wyraźnie określone w paragrafie 1.9 / 4:

Niektóre inne operacje są opisane w niniejszej Normie Międzynarodowej jako niezdefiniowane (na przykład skutek próby zmodyfikowania obiektu const). [Uwaga: Niniejsza Norma Międzynarodowa nie nakłada żadnych wymagań dotyczących zachowania programów, które zawierają nieokreślone zachowanie . —End note]

Wreszcie, jeśli chodzi o definicję „ obserwowalnego zachowania ”, ust. 1.9 / 8 brzmi następująco:

Najmniejsze wymagania dotyczące zgodnej implementacji to:

- Dostęp do obiektów ulotnych jest oceniany ściśle według reguł abstrakcyjnej maszyny.

- W momencie zakończenia programu wszystkie dane zapisane w plikach będą identyczne z jednym z możliwych wyników, które dałoby wykonanie programu zgodnie z abstrakcyjną semantyką.

- Dynamika wejścia i wyjścia urządzeń interaktywnych powinna odbywać się w taki sposób, aby dane wyjściowe zachęty były faktycznie dostarczane, zanim program będzie oczekiwał na wejście. To, co stanowi urządzenie interaktywne, jest zdefiniowane w implementacji.

Są one łącznie określane jako obserwowalne zachowanie programu . [ Uwaga : Bardziej rygorystyczne powiązania między abstrakcyjną a rzeczywistą semantyką mogą być zdefiniowane przez każdą implementację. - notatka końcowa ]


Czy są sytuacje, w których ta zasada nie ma zastosowania?

O ile mi wiadomo, jedynym wyjątkiem od reguły „ jak gdyby ” jest opcja kopiowania / przenoszenia, która jest dozwolona, ​​nawet jeśli konstruktor kopiujący, konstruktor przenoszenia lub destruktor klasy mają efekty uboczne. Dokładne warunki tego są określone w paragrafie 12.8 / 31:

Gdy spełnione są określone kryteria, implementacja może pominąć konstrukcję kopiowania / przenoszenia obiektu klasy, nawet jeśli konstruktor wybrany do operacji kopiowania / przenoszenia i / lub destruktor obiektu mają efekty uboczne . […]

Andy Prowl
źródło
2
Widziałem ten cytat. To, co nie jest jasne, to definicja obserwowalnego zachowania. Co dokładnie kwalifikuje się jako obserwowalne zachowanie? Skopiuj elizję jako wyjątek od reguły „jak gdyby” jest dość dobrze znana i tak naprawdę nie jest częścią mojego pytania.
Alok Save
2
@AlokSave: Cóż, w standardzie C widzimy, że „Dostęp do ulotnego obiektu, modyfikacja obiektu, modyfikacja pliku lub wywołanie funkcji wykonującej którąkolwiek z tych operacji są efektami ubocznymi”. Przypuszczalnie jest coś równoważnego w standardzie (-ach) C ++. Nieformalnie myślę, że „wszystko, co zmienia jego interakcję ze światem zewnętrznym”.
Oliver Charlesworth,
1
Każde zachowanie, które zmienia stan abstrakcyjnej maszyny (czyli coś, co zmienia przekazaną zmienną lub zmienną globalną albo odczytuje i zapisuje na urządzeniach we / wy).
Mats Petersson
1
Czy to oznacza, że ​​usuwanie nieskończonej pętli, która nic nie robi, jest dozwolone, o ile później nie dzieje się nic obserwowalnego?
harold
5
Należy zauważyć, że dotyczy to tylko programów legalnych . Wszystko, co wywołuje niezdefiniowane zachowanie, jest wyraźnie poza zasięgiem.
vonbrand
15

W C11 reguła nigdy nie jest nazywana tą nazwą. Jednak C, podobnie jak C ++, definiuje zachowanie w kategoriach abstrakcyjnej maszyny. Reguła as-if znajduje się w C11 5.1.2.3p4 i p6 :

  1. W maszynie abstrakcyjnej wszystkie wyrażenia są oceniane zgodnie z semantyką. Rzeczywista implementacja nie musi oceniać części wyrażenia, jeśli może wywnioskować, że jego wartość nie jest używana i że nie są wytwarzane żadne potrzebne efekty uboczne (w tym wszelkie spowodowane wywołaniem funkcji lub dostępem do obiektu ulotnego).

  2. […]

  3. Najmniejsze wymagania dotyczące zgodnej implementacji to:

    • Dostęp do volatileobiektów jest oceniany ściśle według reguł abstrakcyjnej maszyny.
    • W momencie zakończenia programu wszystkie dane zapisane w plikach będą identyczne z wynikiem, jaki dałoby wykonanie programu zgodnie z abstrakcyjną semantyką.
    • Dynamika wejścia i wyjścia urządzeń interaktywnych będzie się odbywać zgodnie z 7.21.3 . Celem tych wymagań jest to, aby niebuforowane lub buforowane wierszowo dane wyjściowe pojawiały się tak szybko, jak to możliwe, aby zapewnić, że komunikaty monitujące faktycznie pojawią się przed programem oczekującym na wejście.

     

    To jest obserwowalne zachowanie programu.

Antti Haapala
źródło
-1

W C, C ++, Ada, Java, SML ... w dowolnym języku programowania dobrze określonym przez opis (zwykle wielu możliwych, niedeterministycznych) zachowań programu (narażonych na szereg interakcji na portach I / O) , nie ma odrębnej reguły „as-if” .

Przykładem odrębnej reguły jest ta, która mówi, że dzielenie przez zero wywołuje wyjątek (Ada, Caml) lub zerowa dereferencja wywołuje wyjątek (Java). Można zmienić regułę, aby określić coś innego i może skończyć z innym języku (które niektórzy ludzie raczej nazwać „dialekt” (*). Wyraźną regułą jest tam, aby podać kilka różnych zastosowań język programowania jak odrębną reguły gramatyczne obejmują niektóre konstrukcje składniowe.

(*) Według niektórych lingwistów dialekt to język posiadający „armię”. w tym kontekście może to oznaczać język programowania bez komitetu i określonej branży redaktorów kompilatorów.

Reguła as-if nie jest odrębną regułą ; nie obejmuje żadnego programu w szczególności i nie jest nawet regułą, którą można by omówić, usunąć lub w jakikolwiek sposób zmienić : tak zwana „reguła” po prostu powtarza, że ​​semantyka programu jest zdefiniowana i może być tylko przenośna (uniwersalna) zdefiniowane w kategoriach widocznych interakcji wykonania programu ze światem „zewnętrznym”.

Światem zewnętrznym mogą być interfejsy I / O (stdio), GUI, a nawet interaktywny interpreter, który wyświetla wynikową wartość czystego języka aplikacyjnego. W językach C i C ++ obejmuje (niejasno określone) dostępy do obiektów ulotnych, co jest innym sposobem na powiedzenie, że niektóre obiekty w danym punkcie muszą być reprezentowane w pamięci ściśle według ABI (Application Binary Interface), bez wyraźnego wspominania o ABI.

Definicja śladu wykonania , zwana także zachowaniem widocznym lub dającym się zaobserwować, definiuje, co należy rozumieć pod pojęciem „reguły jak gdyby”. Reguła as-if próbuje to wyjaśnić, ale czyniąc to, bardziej dezorientuje ludzi niż wyjaśnia, ponieważ daje wyraz bycia dodatkową regułą semantyczną, dającą większą swobodę implementacji.

Podsumowanie:

  • Tak zwana „zasada as-if” nie zwalnia żadnych ograniczeń dotyczących implementacji.
  • Nie można usunąć reguły as-if w żadnym języku programowania określonym w kategoriach widocznego zachowania (ślady wykonania utworzone na potrzeby interakcji ze światem zewnętrznym), aby uzyskać odrębny dialekt.
  • Nie można dodać reguły as-if do żadnego języka programowania, który nie jest określony w zakresie widocznego zachowania.
ciekawy facet
źródło
Jeśli ludzie uważają, że się mylę i istnieje wyraźna „zasada jak gdyby”, dlaczego nie spróbują opisać wariantu C ++ (dialektu) bez tej „reguły”? Co w ogóle oznaczałaby specyfikacja C ++ bez tego? Byłoby absolutnie niemożliwe, aby stwierdzić, czy kompilator jest zgodny. Albo nawet zdefiniować zgodność.
curiousguy