Czy istnieje teoria hierarchii wyjątków?

18

Znam kilkanaście języków programowania, które w pewien sposób mają wyjątki, ale doszedłem do wniosku, że mam dwie „patologiczne” tendencje.

  1. Wydaje się, że nie ma wspólnego wzorca lub hierarchii wyjątków. Każdy język w zasadzie rozwija własną wersję, a jeśli wyjątki staną się standardem, wówczas wyjątki, które można znaleźć w standardzie, byłyby raczej arbitralne (głównie te, które zostały zaimplementowane podczas tworzenia narzędzi językowych, takich jak czytanie kodu źródłowego z ciąg znaków lub wyjątek wywołujący debugger lub taki, który występuje, gdy nie można znaleźć pliku itp.)

  2. Wyjątki określone przez język są bardzo rzadko wykorzystywane przez programy użytkownika. Zwykle występowałby jeden lub dwa popularne wyjątki (na przykład „nie wdrażaj”). Chociaż w większości przypadków programiści będą tworzyć własne wyjątki. (Porównaj to, na przykład, tworząc nowe typy liczbowe lub nowe typy kolekcji).

To wydaje mi się strasznym zaniedbaniem. Skąd nikt nie wie, jakie błędy będą potrzebne w programach użytkownika? Miałem nadzieję na istnienie ładnej hierarchii, podobnej do typów numerycznych, kolekcji, systemu obiektowego itp.

Co gorsza, Goolge i Wikipedia zapewniają bardzo niewielką pomoc na ten temat. Do tej pory znalazłem tylko artykuł na temat wyjątku funkcjonalnego, który otwiera się we fragmencie:

Ten artykuł dowodzi, że leniwe programowanie funkcjonalne nie tylko sprawia, że ​​wbudowany mechanizm obsługi wyjątków nie jest konieczny, ale stanowi potężne narzędzie do opracowywania i przekształcania programów korzystających z wyjątków

(A Functional Theory of Exceptions, Mike Spivey, 1988)

Myślę jednak, że wyjątki są dobre. Nie chcę przekształcać programów korzystających z wyjątków, wręcz przeciwnie, chcę, aby korzystanie z wyjątków było mniej chaotyczne.

Pytanie:

Czy istnieje teoria wyjątków? Jeśli tak, jak się nazywa? Jakie są, jeśli w ogóle, kamienie węgielne, które stanowią ich podstawę?

wvxvw
źródło
wyjątki są raczej nowym wynalazkiem, może mniej niż ~ 20-letnim, wynikającym nieco z „longjmp” C. są w większości związane z OOP. wydaje się, że idealne zastosowanie / teoria / najlepsze praktyki są wciąż w fazie ewolucji. java ma jeden z bardziej rozbudowanych modeli. istnieje wiele „antypatternów” związanych z wyjątkami, jak zauważacie. niektóre z nich związane są z teorią „obliczeń odpornych na uszkodzenia”, która wydaje się nieco w powijakach
vzn
Można uznać wyjątki za podzbiór teorii kontynuacji. Zobacz en.wikipedia.org/wiki/Continuation
jmite
@jmite Wyjątki i kontynuacje są bardzo różne. Wyjątki wiążą się dynamicznie z ich modułami obsługi, a kontynuacje robią to statycznie. Zasadniczo kontynuacje same w sobie nie mogą być użyte do implementacji wyjątków, przynajmniej w obecności typów, patrz np. Typowane wyjątki i kontynuacje nie mogą się wzajemnie wyrażać makro .
Martin Berger,
„Wyjątki określone przez język są bardzo rzadko wykorzystywane przez programy użytkownika”. To prawda! Zdefiniowanie niestandardowych wyjątków jest bardzo rzadko potrzebne. Na przykład python i jego stdlib definiują coś w rodzaju 160 wyjątków. Szanse, że wyjątek, o którym myślisz, nie zostały zdefiniowane, są bardzo małe. Niektóre (większość?) Z tych wyjątków nie są powszechnie znane. Na przykład LookupErroridealnie pasuje do każdego niestandardowego pojemnika, ale wiele osób nawet nie wie, że istnieje.
Bakuriu
1
@jmite Jeszcze jedno spotkanie z wyjątkami przed tym tematem pochodziło z książki Benjamina C. Pierce'a Typy i języki programowania. Gdzie wymienia błędy w kontekście definiowania rodzaju funkcji. Tj. Z jego punktu widzenia błędy są tylko kolejnymi wartościami zwracanymi przez funkcje (i razem z innym argumentem tworzą cały typ, jeśli wolno mi tak powiedzieć).
wvxvw

Odpowiedzi:

8

Istnieje wiele publikacji na temat wyjątków, z kilkoma teoretycznymi badaniami. Oto nieuporządkowana i daleka od pełnej lista z kilkoma przykładami. Niestety nie mam w tej chwili czasu na bardziej ukierunkowaną odpowiedź.

  • B. Randell, Struktura systemu dla tolerancji błędów oprogramowania.
  • JB Goodenough. Obsługa wyjątków: problemy i proponowana notacja.
  • JB Goodenough. Ustrukturyzowana obsługa wyjątków.
  • BG Ryder, ML Soffa, Wpływy na projekt obsługi wyjątków.
  • D. Teller, A. Spiwack, T. Varoquaux, Złap mnie, jeśli potrafisz: W kierunku bezpiecznego, hierarchicznego, lekkiego, polimorficznego i wydajnego zarządzania błędami w OCaml.
  • X. Leroy, F. Pessaux, Analiza typowa nieprzechwyconych wyjątków.
  • R. Miller, A. Tripathi, Problemy z obsługą wyjątków w systemach obiektowych.
  • S. Drew, KJ Gough, J. Ledermann, Implementing Zero-Overhead Exception Handling.
  • B. Stroustrup, Wyjątek Bezpieczeństwo: koncepcje i techniki.
  • D. Malayeri, J. Aldrich, Praktyczne specyfikacje wyjątków.
  • H. Nakano, Konstruktywna formalizacja mechanizmu chwytania i rzucania.
  • A. Nanevski, Rachunek modalny do obsługi wyjątków.
  • P. de Groote, Prosty rachunek wyjątków.
  • H. Thielecke, O wyjątkach i kontynuacjach w obecności państwa.
  • JG Riecke, H. Thielecke, wpisane wyjątki i kontynuacje nie mogą się wzajemnie wyrażać makro.
  • M. van Dooren, E. Steegmans, Łącząc solidność sprawdzonych wyjątków z elastycznością niesprawdzonych wyjątków za pomocą zakotwiczonych deklaracji wyjątków.
  • JA Vaughan, Logiczna interpretacja wyjątków w stylu Java.
  • S. Marlow, S. Peyton Jones, A. Moran, Asynchronous Exceptions in Haskell.
  • B. Jacobs, F. Piessens, Failbox: Zapewnienie bezpiecznej obsługi wyjątków.
Martin Berger
źródło
Wow, wielkie dzięki! Zajmie mi kilka miesięcy (jeśli nie więcej), aby wrócić z pozytywną odpowiedzią :) Teraz jestem rozdarty między kilkoma książkami, nie wiedząc od czego zacząć!
wvxvw
2
Wiele z tych artykułów dotyczy wdrażania lub modelowania wyjątków w językach programowania, a nie sposobu projektowania hierarchii wyjątków. Czy możesz skrócić listę do odpowiednich dokumentów?
Gilles „SO- przestań być zły”
@Gilles Pierwotne pytanie było nieco niejasne. Uważam, że to, co uznaje się za odpowiednie wyjątki, zależy głównie od zastosowania. Jedynym prawdziwym problemem teoretycznym związanym z wyjątkami jest kompromis między (1) łączeniem niespokrewnionych modułów przez wyjątki (dlatego żaden język po Javie nie ma obowiązkowych specyfikacji wyjątków), (2) dając użytkownikowi modułu pewne wskazówki, jakich rodzajów erros można się spodziewać oraz (3) pomoc kompilatora w obsłudze błędów. O ile widzę, nie znaleziono jeszcze naprawdę przekonującego rozwiązania tej zagadki.
Martin Berger
6

Nie wiem, czy istnieje teoria, ale może pojawić się pragmatyczna nauka eksperymentalna.

Najlepszym źródłem, o jakim mogę myśleć, jest Bjarne Stroustrup, The Design and Evolution of C ++, Addison-Wesley, 1994 . Jeśli dobrze pamiętam (jest to bardzo dobra książka, a ludzie pożyczają ją ode mnie i nie zwracają, więc nie mam jej w tej chwili), jest rozdział o wyjątkach. Komitet C ++ pod przewodnictwem Stroustrupa wymagał wielu dowodów empirycznych, że proponowana funkcja była konieczna, zanim byli gotowi dodać ją do definicji języka. Strona Wikipedii o wyjątkach zawiera następujący cytat z tej książki:

Na spotkaniu Palo Alto [C ++] w listopadzie 1991 r. Usłyszeliśmy genialne podsumowanie argumentów za semantyką terminacji popartą zarówno osobistym doświadczeniem, jak i danymi Jima Mitchella (z firmy Sun, wcześniej z Xerox PARC). Jim korzystał z obsługi wyjątków w pół tuzinie języków przez okres 20 lat i był jednym z pierwszych zwolenników semantyki wznawiania jako jeden z głównych projektantów i wdrażaczy systemu Cedar / Mesa firmy Xerox. Jego przesłanie było takie, że zakończenie jest lepsze niż wznowienie; nie jest to kwestia opinii, ale kwestia wieloletniego doświadczenia. Wznowienie jest uwodzicielskie, ale nieważne. Poparł to oświadczenie doświadczeniem z kilku systemów operacyjnych. Kluczowym przykładem był Cedar / Mesa: został napisany przez ludzi, którzy lubili i korzystali z wznowienia, ale po dziesięciu latach użytkowania, zostało tylko jedno użycie wznowienia w systemie pół miliona linii - i było to badanie kontekstowe. Ponieważ wznowienie nie było tak naprawdę konieczne dla takiego zapytania kontekstowego, usunęli go i stwierdzili znaczny wzrost prędkości w tej części systemu. W każdym przypadku, w którym zastosowano wznowienie, na przestrzeni dziesięciu lat stanowiło problem, a bardziej odpowiedni projekt go zastąpił. Zasadniczo każde użycie wznowienia oznaczało brak zachowania odrębnych poziomów abstrakcji. W każdym przypadku, w którym zastosowano wznowienie, na przestrzeni dziesięciu lat stanowiło problem, a bardziej odpowiedni projekt go zastąpił. Zasadniczo każde użycie wznowienia oznaczało brak zachowania odrębnych poziomów abstrakcji. W każdym przypadku, w którym zastosowano wznowienie, na przestrzeni dziesięciu lat stanowiło problem, a bardziej odpowiedni projekt go zastąpił. Zasadniczo każde użycie wznowienia oznaczało brak zachowania odrębnych poziomów abstrakcji.

W C ++ prawdziwą wygraną jest RAII , co znacznie ułatwia obsługę dealokacji zasobów podczas błędów. (To nie eliminuje potrzeby throwi try- catch, ale oznacza, że ​​nie potrzebujesz finally).

Myślę, że rzeczą, która przekonała ich, że potrzebują wyjątków, są ogólne kontenery: pisarz kontenerów nie wie nic o rodzajach błędów, które mogą zawierać zwrócone obiekty (a tym bardziej o tym, jak sobie z nimi poradzić), ale o kodzie, który wstawił te obiekty do kontener musi wiedzieć coś o interfejsie tych obiektów. Ale ponieważ nic nie wiemy o tym, jakie rodzaje błędów mogą generować zawarte w nim obiekty, nie możemy ustandaryzować typów wyjątków. (Przeciwnie: jeśli moglibyśmy standaryzować typy wyjątków, nie potrzebowalibyśmy wyjątków).

Inną rzeczą, której ludzie nauczyli się przez lata, jest to, że specyfikacje wyjątków są trudne do poprawnego przetłumaczenia na język. Zobacz na przykład: http://www.gotw.ca/publications/mill22.htm lub ten: http://www.gotw.ca/gotw/082.htm . (I to nie tylko C ++, programiści Java mają również długie argumenty na temat swoich doświadczeń ze sprawdzonymi i niesprawdzonymi wyjątkami ).

Trochę o historii wyjątków. Klasyczny artykuł to: John B. Goodenough: „Obsługa wyjątków: problemy i proponowana notacja”, Commun. ACM 18 (12): 683–696, 1975. Ale wcześniej znane były wyjątki. Mesa miał je około 1974 r., A PL / I też mogłem je mieć. Ada miała mechanizm wyjątków przed 1980 r. Uważam, że na wyjątki w C ++ największy wpływ miało doświadczenie z językiem programowania CLU Barbary Liskov od około 1976 r. Barbara Liskov: „Historia CLU” w Historii języków programowania --- II , Thomas J. Bergin, Jr. i Richard G. Gibson, Jr. (red.). str. 471-510, ACM, 1996 .

Wędrująca logika
źródło
To interesujące i będę musiał więcej badań, aby lepiej odpowiedzieć. Ale do tej pory: wiem, że istnieje bardzo silny sprzeciw wobec kiedykolwiek używania wyjątków w C ++ (być może anegdota, ale konwencje kodowania iirc stosowane przez Google zabraniały używania wyjątków). Wyjątki sprawdzone przez Javę są z pewnością unikalnym i tym samym interesującym eksperymentem, ale funkcja ta zdobyła tak wiele złych kredytów w ciągu swojej historii ... większość ludzi po prostu ponownie je rzuca w czasie wykonywania (chociaż może to być związane tylko ze składnią).
wvxvw
Jestem bardziej zaznajomiony z klasyfikacją wyjątków Common Lisp, w której próbowali (choć z niewielkim powodzeniem) podzielić je zgodnie z poziomem zagrożenia, jakie stwarzają dla programu. np . serious-conditionvs. simple-conditionTeraz czytam również JL Austinga, w którym klasyfikuje błędy (niezwiązane z programowaniem) na grupy na podstawie tego, jak system nie wykonał zadania (np. Użyte niewłaściwe części kontra nieszczere intencje). Które nie ma natychmiastowego zastosowania do programowania, ale może być po pewnym udoskonaleniu.
wvxvw
@ Wandering Logic Uaktualniłem, ponieważ wyjaśniłeś, dlaczego excpetios C ++ są sux i że wykształcone włączenie funkcji może zniszczyć język.
Val
@wvxvw very strong objectionPrzeciw wyjątkom w C ++ pochodzą z dwóch faktów: nie ma finallykonstrukcji i nikt inny nie używa wyjątków. Pierwszy problem pogarsza także drugi. Oznacza to, że gdy nie masz finally, nie możesz zamknąć zasobu, gdy nastąpi wyjątek. Ponieważ nikt nie korzysta z wyjątków, wszystkie funkcje / interfejsy API unikają ich, musisz dużo zainwestować w przebudowę całej tradycyjnej infrastruktury C ++, łącząc wszystkie funkcje z wyjątkami, aby zacząć czerpać z nich korzyści w kodzie. Ale brak finallyuniemożliwia również takie podejście.
Val
@wvxvw: Konwencje Google zakazują wyjątków przekraczających granice modułów (.so). Wynika to z faktu, że wyjątki w C ++ używają informacji o typie wykonania (RTTI), a Linux nie wykonał dobrego zadania w zakresie wpisywania w czasie wykonywania. W systemie Linux można niezawodnie przekazywać typy wykonawcze między modułami tylko wtedy, gdy skompilowano moduły przy użyciu tej samej wersji tego samego kompilatora i połączono z identyczną wersją libstdc ++. Naprawdę jest to odrzucenie C ++ przez społeczność Linuksa, a nie odrzucenie wyjątków.
Wandering Logic
3

Chciałbym tylko zaznaczyć, że wyjątki są przypadkiem efektu obliczeniowego . Inne efekty obliczeniowe to stan zmienny, operacje wejścia / wyjścia, niedeterminizm, kontynuacje i wiele innych. Więc twoje pytanie może być zadane bardziej ogólnie: w jaki sposób tworzymy hierarchie efektów obliczeniowych, jak je organizujemy i dlaczego mamy te, które mamy, a nie inne itp.

Andrej Bauer
źródło
1
Myślę, że jest to całkowicie nieistotne. Pytanie nie dotyczy modelowania pojęcia wyjątków, ale mapowania go na błędy - myślę, że właściwym sposobem opisania go z perspektywy PLT byłaby teoria hierarchii wyjątków.
Gilles „SO - przestań być zły”
Hmm, masz rację. Naprawiłem odpowiedź, aby to podkreślić, ale myślę, że nie trzeba jej usuwać. Co myślisz?
Andrej Bauer