Dlaczego obsługa wyjątków jest zła?

90

Język Go Google nie ma wyjątków jako wybór projektowy, a Linus z Linuxa nazwał wyjątki bzdurą. Czemu?

joemoe
źródło
2
Twórca ZeroMQ pisze o swoim przekonaniu, że pisanie go w C ++ było błędem (głównie z powodu obsługi błędów) 250bpm.com/blog:4
serbaut
Go może nie mieć wyjątków, ale ma "paniki", z których można "odzyskać" (podczas gdy instrukcje odroczone są nadal wykonywane) i które zapewniają nielokalny przepływ sterowania ...
Kerrek SB
Oto fajny artykuł lighterra.com/papers/exceptionsharmful (obsługa wyjątków uważanych za szkodliwe)
masterxilo
Ahaics, wyjątki mogą być symulowane w Go ze znaczącą formułą , chociaż ten punkt może być bardziej znaczący dla transpilingu z cukru składniowego niż dla ręcznego pisania schematu.
Shelby Moore III

Odpowiedzi:

83

Wyjątki bardzo ułatwiają pisanie kodu, w którym zgłoszenie wyjątku spowoduje przerwanie niezmienników i pozostawienie obiektów w niespójnym stanie. Zasadniczo zmuszają cię do zapamiętania, że ​​prawie każde twoje oświadczenie może potencjalnie rzucić i poprawnie sobie z tym poradzić. Może to być trudne i sprzeczne z intuicją.

Rozważ coś takiego jako prosty przykład:

class Frobber
{
    int m_NumberOfFrobs;
    FrobManager m_FrobManager;

public:
    void Frob()
    {
        m_NumberOfFrobs++;

        m_FrobManager.HandleFrob(new FrobObject());
    }
};

Zakładając, że FrobManagerbędzie deletesię FrobObject, to wygląda OK, prawda? A może nie ... Wyobraź sobie, że albo FrobManager::HandleFrob()albo operator newrzuca wyjątek. W tym przykładzie przyrost wartości m_NumberOfFrobsnie jest wycofywany. Dlatego każdy, kto korzysta z tej instancji programu, Frobberbędzie miał prawdopodobnie uszkodzony obiekt.

Ten przykład może wydawać się głupi (ok, musiałem się trochę rozciągnąć, aby go skonstruować :-)), ale na wynos jest to, że jeśli programista nie myśli ciągle o wyjątkach i upewniając się, że każda permutacja stanu zostanie zmieniona gdy są rzuty, wpadasz w kłopoty.

Na przykład możesz o tym myśleć tak, jak o muteksach. W sekcji krytycznej polegasz na kilku instrukcjach, aby upewnić się, że struktury danych nie są uszkodzone i że inne wątki nie widzą twoich wartości pośrednich. Jeśli którekolwiek z tych stwierdzeń po prostu przypadkowo się nie powiedzie, znajdziesz się w świecie bólu. Teraz usuń blokady i współbieżność i pomyśl o każdej metodzie w ten sposób. Pomyśl o każdej metodzie jak o transakcji permutacji stanu obiektu, jeśli wolisz. Na początku wywołania metody obiekt powinien mieć stan czysty, a na końcu również stan czysty. W międzyczasie zmienna foomoże być niespójna zbar, ale twój kod w końcu to naprawi. Wyjątki oznaczają, że każde z Twoich wypowiedzi może Ci przeszkodzić w dowolnym momencie. W każdej indywidualnej metodzie spoczywa na tobie ciężar, aby to naprawić i wycofać, gdy tak się stanie, lub tak uporządkować operacje, aby rzuty nie wpływały na stan obiektu. Jeśli zrobisz to źle (i łatwo jest popełnić taki błąd), wtedy dzwoniący zobaczy Twoje wartości pośrednie.

Metody takie jak RAII, o którym programiści C ++ uwielbiają wspominać jako ostateczne rozwiązanie tego problemu, bardzo dobrze chronią przed tym problemem. Ale to nie jest srebrna kula. Zapewni to natychmiastowe zwolnienie zasobów, ale nie zwalnia cię od konieczności myślenia o uszkodzeniu stanu obiektu i wywołujących widzenie wartości pośrednich. Tak więc wielu ludziom łatwiej powiedzieć, zgodnie z zasadami stylu kodowania, bez wyjątków . Jeśli ograniczysz rodzaj pisanego kodu, trudniej będzie wprowadzić te błędy. Jeśli tego nie zrobisz, łatwo popełnić błąd.

Napisano całe książki o kodowaniu bezpiecznym dla wyjątków w C ++. Wielu ekspertów pomyliło się. Jeśli jest naprawdę tak złożony i ma tak wiele niuansów, może to dobry znak, że musisz zignorować tę funkcję. :-)

asveikau
źródło
9
Ciekawa odpowiedź, ale nie odzwierciedla ona niczego w moim doświadczeniu programistycznym. Myślę więc, że jest to albo specyficzne dla kultury (może bardziej problem w Javie lub C ++ niż, powiedzmy, Pythonie) lub specyficzne dla domeny.
ddaa
42
Wyjątki napisane w języku zarządzanym przy użyciu wzorca try-catch-final nigdy nie powinny pozostawiać nieprawidłowego stanu, jeśli są poprawnie napisane; ponieważ ostatni blok ma gwarancję wykonania, obiekty mogą być tam cofnięte. Resztą powinny zająć się zmienne wychodzące poza zakres i czyszczenie pamięci.
Robert Harvey
7
@ddaa Problem jest zdecydowanie możliwy w Pythonie. Rezultatem jest zazwyczaj trudny do odtworzenia błąd. Być może byłeś szczególnie skrupulatny lub miałeś szczęście. Ale masz rację, że jest to bardziej problem w C ++, gdzie najczęstszym błędem wynikającym z kiepskiego EH jest wyciek pamięci. Starałem się podkreślić, że przecieki nie są najpoważniejszym problemem. @Robert GC złagodzi wycieki pamięci, ale nie jestem pewien, czy kod zarządzany uwolni Cię od błędu programisty. W szczególności, jeśli ktoś nie zwraca uwagi na bezpieczeństwo wyjątków, ponieważ nie uważa, że ​​to problem w jego języku, nie jest to świetny znak.
asveikau
4
@lzprgmr na pewno są: wyjątki pozwalają ci radzić sobie z różnicami. rodzaje błędów przy diff. miejsca w kodzie. Radzenie sobie z błędem połączenia może wymagać ponownego połączenia, ale nie w środku głęboko zagnieżdżonej funkcji. Chcesz to przekazać menedżerowi połączeń czy coś w tym stylu. Następnie zajmowanie się wartościami zwracanymi zmusza cię do sprawdzania błędów w każdym pojedynczym wywołaniu i bąbelkowania tego ręcznie (np. W przypadku błędu resetowania połączenia). Zwracane wartości kumulują się w zagnieżdżonych wywołaniach: func3 może zwrócić -1, func2 wywołuje func3, zwraca -2 w przypadku swoich błędów, -1 dla func3 itd.
abourget
4
Głosowałem przeciw, ale odwróciłem to, ponieważ jest to powód, dla którego wyjątki są traktowane z góry. Jednak moim zdaniem prawie każda metoda lub fragment kodu może zawieść. Nie można obsłużyć każdego warunku błędu, wprowadzając dla niego wartość zwracaną. Utracisz informacje o błędzie. Myślenie, że można wszystko ładnie zsynchronizować, sprawdzając każdą instrukcję i wykonując czyszczenie, prowadzi do bardzo zawiłego kodu - wychwycenie błędu w wielu instrukcjach i wyczyszczenie jednego lub dwóch zasobów, które nie są objęte GC, jest znacznie czystsze.
Maarten Bodewes
50

Powód, dla którego w Go nie ma wyjątków, wyjaśniono w często zadawanych pytaniach dotyczących projektowania języka Go:

Wyjątki to podobna historia. Zaproponowano wiele projektów wyjątków, ale każdy z nich znacznie komplikuje język i czas wykonywania. Ze swej natury wyjątki obejmują funkcje, a być może nawet gorutynę; mają daleko idące konsekwencje. Istnieją również obawy co do wpływu, jaki wywrą one na biblioteki. Są z definicji wyjątkowe, ale doświadczenie z innymi językami, które je obsługują, pokazuje, że mają one głęboki wpływ na specyfikację biblioteki i interfejsu. Byłoby miło znaleźć projekt, który pozwala im być naprawdę wyjątkowymi bez zachęcania do zwykłych błędów do przekształcenia się w specjalny przepływ sterowania, który wymaga od każdego programisty kompensacji.

Podobnie jak produkty generyczne, wyjątki pozostają otwartą kwestią.

Innymi słowy, jeszcze nie wymyślili, jak obsługiwać wyjątki w Go w sposób, który ich zdaniem jest zadowalający. Nie mówią, że wyjątki są złe same w sobie ;

AKTUALIZACJA - maj 2012

Projektanci Go zeszli teraz z ogrodzenia. Ich FAQ mówi teraz tak:

Uważamy, że łączenie wyjątków ze strukturą kontrolną, jak w idiomie try-catch-last, skutkuje zawikłaniem kodu. Ma również tendencję do zachęcania programistów do oznaczania zbyt wielu zwykłych błędów, takich jak niepowodzenie otwarcia pliku, jako wyjątkowych.

Go ma inne podejście. W przypadku zwykłej obsługi błędów zwroty wielowartościowe Go ułatwiają zgłoszenie błędu bez przeciążania zwracanej wartości. Kanoniczny typ błędu w połączeniu z innymi funkcjami Go sprawia, że ​​obsługa błędów jest przyjemna, ale zupełnie inna niż w innych językach.

Go ma również kilka wbudowanych funkcji do sygnalizowania i przywracania sprawności po naprawdę wyjątkowych warunkach. Mechanizm przywracania jest wykonywany tylko wtedy, gdy stan funkcji jest niszczony po błędzie, co jest wystarczające do obsługi katastrofy, ale nie wymaga żadnych dodatkowych struktur sterujących, a jeśli jest dobrze używane, może skutkować czystym kodem obsługi błędów.

Szczegółowe informacje można znaleźć w artykule Odraczanie, panika i odzyskiwanie.

Krótka odpowiedź jest taka, że ​​mogą to zrobić inaczej, używając zwrotu z wielu wartości. (I tak mają formę obsługi wyjątków).


... a Linus znany z Linuksa nazwał wyjątki bzdurą.

Jeśli chcesz wiedzieć, dlaczego według Linusa wyjątki to bzdury, najlepiej poszukaj jego prac na ten temat. Jedyną rzeczą, którą do tej pory wyśledziłem, jest ten cytat, który jest osadzony w kilku e-mailach w C ++ :

„Cała obsługa wyjątków w C ++ jest zasadniczo zepsuta. Jest szczególnie zepsuta w przypadku jądra”.

Zauważysz, że mówi on w szczególności o wyjątkach C ++, a nie ogólnie o wyjątkach. (A wyjątki C ++ mają najwyraźniej pewne problemy, które utrudniają ich prawidłowe użycie).

Mój wniosek jest taki, że Linus w ogóle nie nazwał wyjątków (ogólnie) „bzdurami”!

Stephen C.
źródło
30
Nienawidzę, kiedy ukrywają informacje, umieszczając je w FAQ. :)
brian d foy
7
Zauważ, że Linus zaczyna tę wiadomość od „C ++ to okropny język”. i dalej narzekał na to, jak bardzo nienawidzi zarówno C ++, jak i ludzi, którzy decydują się na programowanie w tym języku. W związku z tym nie sądzę, aby jego opinia na temat wyjątków w C ++ była wiarygodna, biorąc pod uwagę jego nieco stronniczą opinię na temat C ++.
Pharap,
1
@ Hi-Angel - Zgodnie z cytowanym przeze mnie tekstem: „W przypadku zwykłej obsługi błędów wielowartościowe zwroty Go ułatwiają zgłoszenie błędu bez przeciążania zwracanej wartości”. . Tak to jest powiązane. Tak czy inaczej, cytuję uzasadnienie projektantów Go. Jeśli chcesz się kłócić, spieraj się z >> nimi <<.
Stephen C
1
@ Hi-Angel - nie napisałem tych akapitów. Po prostu je zacytowałem. Jeśli masz z nimi problem, prawdopodobnie powinieneś porozmawiać z autorami. Teoretycznie mógłbym podać samouczek na temat języka Go jako kontekstu. Ale szczerze mówiąc, osoby, które nie rozumieją terminologii Go, mogą odwiedzić witrynę Go, aby dowiedzieć się, co to wszystko oznacza.
Stephen C
1
".. skutkuje zagmatwanym kodem" Dawno temu napisałem program w C z wieloma operacjami na łańcuchach. Każda metoda polegała na przydzieleniu pamięci, a następnie sprawdzeniu, czy alokacja się powiodła. Okazało się, że większość kodu tylko sprawdzała alokacje. Czy to nie jest zagmatwane? C ++ z wyjątkami był dla mnie świetnym ratunkiem.
robsosno
29

Wyjątki same w sobie nie są złe, ale jeśli wiesz, że będą się często zdarzać, mogą być kosztowne pod względem wydajności.

Ogólna zasada jest taka, że ​​wyjątki powinny oznaczać wyjątkowe warunki i nie należy ich używać do sterowania przepływem programu.

Robert Harvey
źródło
9
@Robert: "nie należy ich używać do sterowania przebiegiem programu", nie myślałem o tym w ten sposób, nowa perspektywa dla mnie: P +1
okw
2
Zależy to również od języka. Trudno jest uniknąć wyjątków, jeśli na przykład programujesz w języku Java.
Charles Salvia,
2
@Charles: Myślę, że chodzi o to, że wyjątki są odpowiednie w sytuacjach, które wskazują na błąd, błędną konfigurację systemu lub nieuzasadnione dane wejściowe. Większości wyjątków dotyczących bibliotek Java można uniknąć w kodzie „normalnego przepływu pracy”.
Artelius
6
nie muszą dużo kosztować. na przykład, możesz zaimplementować "try", które kosztuje zero czasu wykonania, i mieć "rzucanie" sprawdzania obsługi wyjątków w tabeli na podstawie adresów wywołujących, które widzi na stosie ... Powiedziałbym, że największe powody, aby tego nie robić wyjątki dotyczące użytkowania nie są w ogóle związane z wydajnością.
asveikau
Przeformułowane; pytanie wyraźnie wskazuje na używanie wyjątków w ogóle lub nie używanie wyjątków w ogóle (są one bzdurne lub nawet nie są w języku). Twoja odpowiedź pokazuje tylko, dlaczego wyjątki są niekorzystne dla wydajności, gdy są używane do przepływu sterowania programem.
Maarten Bodewes
26

Nie zgadzam się z zasadą „wyrzucaj wyjątki tylko w wyjątkowych sytuacjach”. Chociaż ogólnie jest to prawdą, jest to mylące. Wyjątki dotyczą warunków błędu (niepowodzenia wykonania).

Niezależnie od używanego języka, pobierz kopię Wytycznych dotyczących projektowania platformy: konwencje, idiomy i wzorce dla bibliotek .NET wielokrotnego użytku (wydanie drugie). Rozdział o rzucaniu wyjątków jest bez peera. Kilka cytatów z pierwszej edycji (druga w mojej pracy):

  • NIE zwracaj kodów błędów.
  • Kody błędów można łatwo zignorować i często tak jest.
  • Wyjątki są głównym sposobem zgłaszania błędów w ramach.
  • Dobra praktyczna zasada jest taka, że ​​jeśli metoda nie robi tego, co sugeruje jej nazwa, należy ją uznać za błąd na poziomie metody, powodując wyjątek.
  • Jeśli to możliwe, NIE WOLNO stosować wyjątków dla normalnego przepływu sterowania.

Istnieją strony z uwagami na temat zalet wyjątków (spójność interfejsu API, wybór lokalizacji kodu obsługi błędów, ulepszona niezawodność itp.). Sekcja dotycząca wydajności zawiera kilka wzorców (Tester-Doer, Try-Parse).

Wyjątki i obsługa wyjątków nie są złe. Jak każda inna funkcja, mogą być nadużywane.

TrueWill
źródło
4
Muszę się z tym nie zgodzić. Nie jestem przeciwny wyjątkom i ta książka jest koniecznością, jednak jest nastawiona na rozwój .NET i C #.
3
Wiem, że jest to starożytne, chciałem tylko skomentować, że wydaje się, że wystąpiłby ogólny spór między typami .NET i * nix. Wszystkie biblioteki, których używałem jako programista Linuksa, używają kodów powrotu, a przewodniki w stylu * nix, które przeczytałem (na przykład moja firma i Google ), po prostu mówią „nie robimy wyjątków”. Pomyśl tylko, że to interesujące.
jarvisteve
1
Struktury powinny traktować wyjątki inaczej niż aplikacje użytkowników końcowych. Struktury nie mają innego sposobu radzenia sobie z błędami niż zgłaszanie wyjątku, co robią aplikacje konsumenckie.
0x6C38
11

Z punktu widzenia golanga, myślę, że brak obsługi wyjątków sprawia, że ​​proces kompilacji jest prosty i bezpieczny.

Z perspektywy Linusa rozumiem, że kod jądra jest WSZYSTKIM związany z przypadkami narożnymi. Dlatego warto odmawiać wyjątków.

Wyjątki mają sens w kodzie, w których można upuścić bieżące zadanie na podłogę i gdzie typowy kod przypadku ma większe znaczenie niż obsługa błędów. Ale wymagają generowania kodu przez kompilator.

Na przykład sprawdzają się w większości kodu wysokiego poziomu dla użytkownika, takiego jak kod aplikacji internetowej i komputerowej.

ddaa
źródło
Ale to, co jest prawdą w przypadku kodu jądra, jest również prawdziwe w przypadku długo działających natywnych procesów serwera.
Lothar
11

Wyjątki same w sobie nie są „złe”, to sposób, w jaki czasami obsługiwane są wyjątki, jest zwykle zły. Istnieje kilka wskazówek, które można zastosować podczas obsługi wyjątków, aby złagodzić niektóre z tych problemów. Niektóre z nich obejmują (ale z pewnością nie są ograniczone do):

  1. Nie używaj wyjątków do sterowania przepływem programu - tj. Nie polegaj na instrukcjach „catch” w celu zmiany przepływu logiki. Nie tylko ma to tendencję do ukrywania różnych szczegółów związanych z logiką, ale może prowadzić do słabej wydajności.
  2. Nie zgłaszaj wyjątków z wnętrza funkcji, gdy zwrócony „status” miałby większy sens - zgłaszaj wyjątki tylko w wyjątkowych sytuacjach. Tworzenie wyjątków to kosztowna operacja wymagająca dużej wydajności. Na przykład, jeśli wywołasz metodę otwierania pliku, a ten plik nie istnieje, zgłoś wyjątek „FileNotFound”. Jeśli wywołasz metodę, która określa, czy konto klienta istnieje, zwróć wartość logiczną, nie zwracaj wyjątku „CustomerNotFound”.
  3. Podczas określania, czy obsłużyć wyjątek, czy nie, nie używaj klauzuli „try ... catch”, chyba że możesz zrobić coś pożytecznego z wyjątkiem. Jeśli nie jesteś w stanie obsłużyć wyjątku, po prostu pozwól mu zwiększyć stos wywołań. W przeciwnym razie wyjątki mogą zostać „połknięte” przez program obsługi, a szczegóły zostaną utracone (chyba że ponownie wyrzucisz wyjątek).
Jeff Bramwell
źródło
2
Powrót statusu to trudna sprawa. Widziałem o wiele za dużo kodu, który ma metodę GetCustomer zwracającą jednostkę Customer w przypadku sukcesu lub zerową w przypadku niepowodzenia. W wielu przypadkach kod wywołujący nigdy nie sprawdzał wyniku, ale natychmiast uzyskiwał dostęp do klienta. To działało przez większość czasu ...
TrueWill
3
Ale jeśli GetCustomer zgłosi wyjątek zamiast zwracać wartość null, kod klienta nadal musi obsługiwać wyjątek. Niezależnie od tego, czy chodzi o sprawdzanie wartości null, czy przez obsługę wyjątków, odpowiedzialność spoczywa na kodzie klienta - jeśli nie robi jakich rzeczy poprawnie, to tak czy inaczej, prędzej czy później coś eksploduje.
Chris
1
@TrueWill Języki obsługujące szablony / typy generyczne rozwiązują ten problem, zwracając Option<T>zamiast nullobecnie. Właśnie zostałem wprowadzony na przykład w Javie 8, czerpiąc wskazówkę z guawy (i innych).
Maarten Bodewes
@owlstead Yep. Uwielbiam może monadę. To dobry sposób, jeśli twój język to obsługuje i oferuje dopasowywanie wzorców.
TrueWill
@owlstead Ponownie, to, co powiedział Chris, wciąż jest do tego mocne - użytkownik musi pamiętać o wywołaniu funkcji .orElse (defaultObject) lub dowolnego idiomu, który zdecydował dany język. Ostatecznie to ostatecznie programiści są problemem, a nie metoda obsługi błędów.
Pharap,
9

Typowe argumenty są takie, że nie ma sposobu, aby stwierdzić, jakie wyjątki wyjdą z określonego fragmentu kodu (w zależności od języka) i że są one zbyt podobne do gotos, co utrudnia myślowe śledzenie wykonania.

http://www.joelonsoftware.com/items/2003/10/13.html

Zdecydowanie nie ma konsensusu w tej kwestii. Powiedziałbym, że z punktu widzenia twardego programisty C, takiego jak Linus, wyjątki są zdecydowanie złym pomysłem. Jednak typowy programista Java jest w zupełnie innej sytuacji.

Tim Sylvester
źródło
1
Kod C ma trochę wyjątków, tylko w inny sposób. Musisz zawijać każde wywołanie nietrywialnej funkcji w ifs, co sprawia, że ​​używanie tego języka przyprawia o ból głowy!
RCIX
1
Jest też setjmp/ longjmprzecz, która jest dość zła.
Tim Sylvester
9
Czy naprawdę chcesz skorzystać z rady człowieka, który ceni programistów taśm Duct i nie wierzy, że testy jednostkowe są konieczne? joelonsoftware.com/items/2009/09/23.html
TrueWill
4
To klasyczny błąd (lub oszustwo) w dyskusji, w której argumenty na ten temat są zastępowane odwołaniami do osobowości. To zwykle znak degenerującej się dyskusji.
Petr Gladkikh
1
@PetrGladkikh Dyskusja rozpoczęła się od PO odwołując się do opinii Linusa ... że oszustwo jest znane jako błąd odwołania się do władzy. Od tego momentu dyskusja może iść tylko pod górę i nie jest „oszustwem” odpowiadanie na pytanie, dlaczego Linus nie lubi wyjątków, odwołując się do swojej osobowości.
Jim Balter
7

Wyjątki nie są złe. Dobrze pasują do modelu RAII w C ++, który jest najbardziej elegancką cechą C ++. Jeśli masz już kilka kodów, które nie są bezpieczne pod względem wyjątków, są one złe w tym kontekście. Jeśli piszesz oprogramowanie naprawdę niskiego poziomu, takie jak system operacyjny Linux, to jest złe. Jeśli lubisz zaśmiecać swój kod kilkoma sprawdzeniami zwrotów błędów, to nie są one pomocne. Jeśli nie masz planu kontroli zasobów, gdy zostanie zgłoszony wyjątek (który zapewnia destruktory C ++), to są złe.

Paweł
źródło
7
RAII jest przydatne nawet bez wyjątków.
Mark Ransom
4
jednak wyjątki nie są przydatne bez RAII (lub innego automatycznego zarządzania zasobami).
Greg Rogers
+1 za wskazanie sytuacji, w których wyjątki nie są odpowiednie, a wyjątki nie są z natury złe.
Pharap
4

Świetnym przykładem użycia wyjątków jest zatem ...

Powiedzmy, że pracujesz nad projektem i każdy kontroler (około 20 różnych głównych) rozszerza pojedynczy kontroler nadklasy o metodę akcji. Wtedy każdy kontroler wykonuje różne rzeczy, wywołując obiekty B, C, D w jednym przypadku i F, G, D w innym. Wyjątki przychodzą tutaj na ratunek w wielu przypadkach, gdy było mnóstwo kodu zwrotnego i KAŻDY kontroler obsługiwał go inaczej. Uderzyłem cały ten kod, wrzuciłem odpowiedni wyjątek z "D", złapałem go w metodzie akcji kontrolera nadklasy i teraz wszystkie nasze kontrolery są spójne. Poprzednio D zwracał wartość null dla WIELU różnych przypadków błędów, o których chcemy poinformować użytkownika końcowego, ale nie mogłem, a ja nie.

tak, musimy się martwić o każdy poziom i wszelkie czyszczenie / wycieki zasobów, ale ogólnie żaden z naszych kontrolerów nie miał żadnych zasobów do wyczyszczenia.

dzięki Bogu mieliśmy wyjątki, bo inaczej byłbym narażony na ogromny refaktor i straciłbym zbyt dużo czasu na coś, co powinno być prostym problemem programistycznym.

Dean Hiller
źródło
1
+1 Z łatwością jeden z najlepszych argumentów przemawiających za używaniem wyjątków, które przeczytałem. Mogłem użyć bardziej szczegółowych przykładów (np. Diagram UML, jakiś pseudokod lub jakiś rzeczywisty kod), ale kwestia zapewnienia spójnego działania podklas jest dobra. Ponadto fakt, że twoje dowody są anegdotyczne, pokazuje, że wyjątki są przydatne w rzeczywistych sytuacjach, a użyteczność jest głównym celem każdej funkcji języka.
Pharap,
po prostu jako dodatek, jeśli jesteś w scali, możesz zamiast tego zwrócić Try [ResponseType], który reprezentuje wyjątek lub rzeczywistą odpowiedź. Następnie możesz postępować zgodnie z tym samym schematem, którego unikam powyżej, bez rzeczywistych wyjątków innych niż te, które są stosowane podczas próby. Wtedy jest tak, jak każda metoda, którą masz, zwraca 1 + n typów odpowiedzi, które moim zdaniem są potrzebne. Jednak w scali zwracamy Future [odpowiedź], która działa podobnie jak Try, ale może pomóc w programowaniu bardziej asynchronicznym.
Dean Hiller
2

Teoretycznie są naprawdę złe. W idealnym matematycznym świecie nie można znaleźć sytuacji wyjątkowych. Spójrz na języki funkcjonalne, nie mają skutków ubocznych, więc praktycznie nie mają źródła nietypowych sytuacji.

Ale rzeczywistość to inna historia. Zawsze mamy sytuacje, które są „nieoczekiwane”. Dlatego potrzebujemy wyjątków.

Myślę, że możemy myśleć o wyjątkach jako o cukrze składni dla ExceptionSituationObserver. Otrzymujesz tylko powiadomienia o wyjątkach. Nic więcej.

Myślę, że wraz z Go wprowadzą coś, co poradzi sobie z „nieoczekiwanymi” sytuacjami. Domyślam się, że postarają się, aby brzmiało to mniej destrukcyjnie jako wyjątki, a bardziej jako logika aplikacji. Ale to tylko moje przypuszczenie.

Mike Chaliy
źródło
2
„Spójrz na języki funkcjonalne, nie mają skutków ubocznych, więc praktycznie nie mają źródła dla nietypowych sytuacji”. To rażąca przesada.
Stephen C
3
Co to jest 5/0 w matematyce? Arcsin (200)? Sqrt (-1)? Matematyka ma mnóstwo wyjątkowych sytuacji.
Robert Fraser,
3
To nie są sytuacje wykonawcze ... po prostu nie mają znaczenia ... i dlatego mogą być zaimplementowane jako wyjątki ... ale mogą być również zaimplementowane jako vialacje warunków wstępnych ... więc zależy to od implementacji technicznej.
Mike Chaliy
3
@MikeChaliy - Przepraszam, ale to tylko sofistyka. Możesz zastosować tego rodzaju rozumowanie, aby powiedzieć, że NIGDY nie ma żadnych wyjątków. W rzeczywistości wyrażenia matematyczne, które nie mają znaczenia (lub nie mają określonej wartości), SĄ wyjątkowe. Nie oznacza to, że trzeba sobie z nimi radzić, rzucając i przechwytując wyjątki ... ale jeśli tego nie zrobisz, potrzebujesz specjalnych wartości (takich jak Inf i Nan) lub operacji, które zwracają wiele wartości. Krótko mówiąc, takie przypadki wymagają specjalnego traktowania.
Stephen C
1
Komputery to maszyny stanowe. Nie jest to doskonały świat matematyki.
Arunav Sanyal
1

Paradygmat obsługi wyjątków w C ++, który stanowi częściową podstawę dla języka Java, a co za tym idzie .net, wprowadza kilka dobrych koncepcji, ale ma też pewne poważne ograniczenia. Jedną z kluczowych intencji projektowych obsługi wyjątków jest umożliwienie metodom zapewnienia, że ​​spełnią one swoje warunki końcowe lub wyrzucą wyjątek, a także zapewnienie, że nastąpi czyszczenie, które musi nastąpić przed zakończeniem metody. Niestety, wszystkie paradygmaty obsługi wyjątków w językach C ++, Java i .net nie zapewniają żadnego dobrego sposobu radzenia sobie z sytuacją, w której nieoczekiwane czynniki uniemożliwiają wykonanie oczekiwanego czyszczenia. To z kolei oznacza, że ​​trzeba albo ryzykować, że wszystko zatrzyma się z piskiem, jeśli wydarzy się coś nieoczekiwanego (podejście C ++ do obsługi wyjątku występuje podczas rozwijania stosu),

Nawet jeśli obsługa wyjątków byłaby ogólnie dobra, nie jest nierozsądne uznanie za niedopuszczalny paradygmatu obsługi wyjątków, który nie zapewnia dobrych środków do obsługi problemów, które pojawiają się podczas czyszczenia po innych problemach. Nie oznacza to, że frameworku nie można zaprojektować z paradygmatem obsługi wyjątków, który mógłby zapewnić rozsądne zachowanie nawet w scenariuszach wielu niepowodzeń, ale żaden z najlepszych języków ani frameworków nie może tego zrobić.

supercat
źródło
1

Nie przeczytałem wszystkich innych odpowiedzi, więc już o tym wspominałem, ale jedną z zarzutów jest to, że powodują one zrywanie programów w długie łańcuchy, co utrudnia wyśledzenie błędów podczas debugowania kodu. Na przykład, jeśli Foo () wywołuje Bar (), która wywołuje Wah (), która wywołuje ToString (), to przypadkowe przesłanie niewłaściwych danych do ToString () kończy się wyglądaniem jak błąd w Foo (), prawie całkowicie niepowiązanej funkcji.

kingfrito_5005
źródło
0
  • Nieobsługiwany wyjątek jest ogólnie zły.
  • Wyjątek obsługiwany źle jest zły (oczywiście).
  • „Dobro / zło” obsługi wyjątków zależy od kontekstu / zakresu i stosowności, a nie po to, aby to zrobić.
okw
źródło
0

OK, nudna odpowiedź tutaj. Myślę, że tak naprawdę zależy to od języka. Tam, gdzie wyjątek może pozostawić przydzielone zasoby, należy ich unikać. W językach skryptowych po prostu porzucają lub zastępują części przepływu aplikacji. Samo w sobie jest to nie do przyjęcia, ale unikanie błędów prawie krytycznych z wyjątkami jest akceptowalnym pomysłem.

Generalnie preferuję sygnały błędów do sygnalizacji błędów. Wszystko zależy od interfejsu API, przypadku użycia i ważności lub tego, czy wystarczy logowanie. Próbuję też przedefiniować zachowanie i throw Phonebooks()zamiast tego. Chodzi o to, że „Wyjątki” są często ślepymi uliczkami, ale „Książka telefoniczna” zawiera przydatne informacje na temat usuwania błędów lub alternatywnych tras wykonywania. (Nie znalazłem jeszcze dobrego przypadku użycia, ale próbuj dalej).

mario
źródło
0

Dla mnie sprawa jest bardzo prosta. Wielu programistów niewłaściwie używa obsługi wyjątków. Więcej zasobów językowych jest lepsze. Umiejętność obsługi wyjątków jest dobra. Jednym z przykładów złego użycia jest wartość, która musi być liczbą całkowitą, której nie można zweryfikować, lub inne dane wejściowe, które mogą dzielić i nie być sprawdzane pod kątem dzielenia zer ... obsługa wyjątków może być łatwym sposobem na uniknięcie dodatkowej pracy i ciężkiego myślenia, może chcieć zrobić nieprzyjemny skrót i zastosować obsługę wyjątków ... Stwierdzenie: „profesjonalny kod NIGDY nie zawodzi” może być iluzoryczne, jeśli niektóre z problemów przetwarzanych przez algorytm są z natury niepewne. Być może w nieznanych z natury sytuacjach dobrze jest wejść do gry z obsługą wyjątków. Dobre praktyki programowania są przedmiotem dyskusji.

iuri
źródło
Problemem nie jest (lub nie powinno być) to, czy kod może zawieść - większym problemem jest to, w jakim stopniu, jeśli kod się nie powiedzie, zależy nam na szczegółach. Jeśli ktoś próbuje załadować dokument i jedna z metod „odczytu danych” zawodzi, często nie obchodzi nas, która z nich, ponieważ efekt jest taki sam, niezależnie od tego: dokumentu nie można załadować. Pod względem koncepcyjnym obsługa wyjątków powinna być do tego dobra. Problem polega na tym, że paradygmaty obsługi wyjątków w .NET i Javie nie zapewniają żadnego dobrego sposobu na odróżnienie „nudnych” wyjątków, które powinny być łączone razem, od tych, które nie powinny.
supercat