Dlaczego opcja / może jest uważana za dobry pomysł, a sprawdzone wyjątki nie są?

23

Niektóre języki programowania, takie jak np. Scala, mają pojęcie Optiontypów (zwanych także Maybe), które mogą zawierać wartość lub nie.

Z tego, co o nich czytałem, są one powszechnie uważane za lepszy sposób radzenia sobie z tym problemem niż null, ponieważ wyraźnie zmuszają programistę do rozważenia przypadków, w których może nie być żadnej wartości zamiast po prostu wysadzenia w powietrze w czasie wykonywania.

Z drugiej strony sprawdzone wyjątki w Javie wydają się być złym pomysłem, a Java wydaje się być jedynym powszechnie używanym językiem, który je implementuje. Ale idea za nimi wydaje się być nieco podobna do Optiontypu, aby wyraźnie zmusić programistę do radzenia sobie z faktem, że może zostać zgłoszony wyjątek.

Czy są jakieś dodatkowe problemy z zaznaczonymi wyjątkami, Optionktórych nie mają typy? Czy te pomysły nie są tak podobne, jak myślę, i istnieją uzasadnione powody, aby wymuszać jawną obsługę Opcji, a nie wyjątków?

Szalony naukowiec
źródło
Zobacz także Either e atyp danych.
4
O sprawdzonych wyjątkach: jako użytkownik wielu bibliotek Open Source i wewnętrznych bibliotek Java z rozwijającą się bazą kodu i brakującymi / nieaktualnymi dokumentami, wzdrygam się na myśl, że Java nie wymusi jawnego zadeklarowania pewnych wyjątków. Byłby to koszmar nieobsługiwanych błędów środowiska wykonawczego pojawiających się w nieoczekiwanych miejscach. A Java7 w końcu sprawia, że ​​obsługa wyjątków jest prawie normalna, pozbywając się dużej części starego bałaganu typu try-catch.
hyde

Odpowiedzi:

24

Ponieważ Options są składalne. Istnieje wiele przydatnych metod na Optionktóre pozwalają pisać kod zwięzły, a jednocześnie pozwala na precyzyjne sterowanie przepływem: map, flatMap, toList, flatteni więcej. Wynika to z faktu, że Optionjest to szczególny rodzaj monady, niektórych obiektów, które wiemy bardzo dobrze, jak komponować. Jeśli nie posiadałeś tych metod i musiałeś zawsze dopasowywać wzór Optionlub isDefinedczęsto dzwonić , nie byłyby one tak przydatne.

Zamiast tego, chociaż zaznaczone wyjątki zwiększają bezpieczeństwo, niewiele można z nimi zrobić, poza złapaniem ich lub pozwoleniem, by wybrzuszały się w stosie (z dodaną płytką kotłową w deklaracji typu).

Andrea
źródło
1
Sprawdzone wyjątki składają się mniej więcej na te same sposoby ... Różnica między try {/* bunch of complex code involving calls to 50 different methods that may throw SomeCheckedException */} catch(SomeCheckedException e) {/* operation failed, do something */}i fromMaybe someDefaultValue (something >>= otherThing >>= ...50 other functions that may return Nothing...)co dokładnie? Poza tym, że ten pierwszy zawiera więcej szczegółów na temat tego, co poszło nie tak.
user253751
14

Chociaż są powiązane, wyjątki i być może obiekty nie dotyczą tego samego rodzaju problemów.

Wyjątki

Wyjątki naprawdę świecą, gdy musisz poradzić sobie z sytuacją wyjątkową (niekiedy lokalną). Na przykład analizujesz plik csv i chcesz zabezpieczyć się przed liniami z niewłaściwym formatowaniem. Miejscem, w którym zauważysz, że coś jest nie tak, mogą być niektóre wywołania funkcji z dala od iteracji linii. Jeśli rzucisz wyjątek na najgłębszym poziomie (gdzie dowiesz się o problemach z formatowaniem), możesz złapać go w pętli, zarejestrować błąd i przejść do następnego wiersza. Nie musisz niczego modyfikować w pozostałej części kodu.

Sprawdzony wyjątek powoduje wiele bólu, ponieważ wszystkie funkcje pośrednie muszą zadeklarować typ rzucalny. Funkcja pokonuje pierwotny cel, dlatego nie są obecnie popularne.

Może przedmioty

Może obiekty powinny być wybierane, gdy jesteś w stanie poradzić sobie lokalnie z „niepowodzeniem”. W tym sensie zastępują one kod powrotu + przekazanie przez interfejs API lub typ zerowy.

Zaletą obiektu Może jest to, że wyraźnie deklarujesz, że coś może być nie tak. W haskell obiekt, który może nie jest, musi mieć wartość, w przeciwnym razie program się nie skompiluje.

Problem z typami zerowalnymi polega na tym, że musisz cały czas sprawdzać wartość null, aby być całkowicie bezpiecznym. Domyślnym stanem jest „coś może być nie tak”.

Problem z kodami powrotu + przekazywaniem przez ap api polega na tym, że są one mniej czytelne dla większości ludzi.

Simon Bergot
źródło
1
@MattFenwick dzięki za opinie. Dlaczego uważasz, że przykład CSV nie ma sensu? OP tak naprawdę nie prosi o techniki unikania bojlerów i mam wrażenie, że słownictwo, takie jak funktor aplikacyjny i monady, może być zbyt techniczne na to pytanie.
Simon Bergot
1
Chciałbym zauważyć, że w Javie (nie jestem pewien innych języków z zaznaczonymi wyjątkami) środowiska IDE zajmują się dodawaniem i przycinaniem rzutów oraz aktualizowaniem części zawierającej komentarze javadoc. Więc przynajmniej ta część nie przeszkadza, a na pewno nie ma bólu. Niezależnie od tego, czy jest to ból, dar, czy coś pośredniego podczas projektowania interfejsu API, to inna sprawa ...
hyde
5
@hyde: Tylko dlatego, że IDE może zautomatyzować bezcelowe generowanie płyt kotłowych, nie oznacza, że ​​bezcelowa płytka kotłowa nie jest problemem.
Michael Shaw
2
@hyde: Ale ból nie został usunięty. Bezsensowna płyta kotła wciąż tam jest, zaśmiecając kod bez powodu. Jeśli istnieje przyczyna płyty kotłowej, co to jest?
Michael Shaw
2
@MichaelShaw Jeśli wyjątek jest bezcelowy, usuń go: zignoruj ​​sytuację lub zwróć zamiast tego wartość błędu. Jeśli jest to błąd lub sytuacja niemożliwa do odzyskania: użyj niezaznaczonego wyjątku. To, co pozostaje, jest równie ważne, jak na przykład typy parametrów, a nie bezsensowna płyta kotła. Jeśli jest to zły interfejs API w istniejącej bibliotece lib, rozważ metodę opakowania / klasę, używając innej biblioteki lub po prostu cierpiący na zły interfejs API.
hyde
1

ponieważ dzięki Maybeniemu możesz opóźnić obsługę błędu, aż faktycznie potrzebujesz wartości (może to być kilka wywołań metody)

podczas gdy sprawdzony wyjątek musi być obsługiwany w miejscu połączenia

jedyną zaletą wyjątków jest to, że można przekazać więcej informacji na temat przyczyny niepowodzenia (chyba że ktoś opracuje pole MaybeErrorz możliwością rzucania, gdy jest to błąd)

maniak zapadkowy
źródło
2
Ale mogę odroczyć obsługę sprawdzonego wyjątku, deklarując, że moja metoda zgłasza ten wyjątek.
Szalony naukowiec
1
@MadScientist, który idzie w górę stosu wywołań, podczas gdy być może może iść we wszystkich kierunkach
maniak ratchet
5
Myślę, że nie należy mylić Maybetypów z błędami obsługi. Do zgłoszenia błędu używany jest wyjątek, typ opcji służy do przedstawienia wyniku funkcji częściowej. Częściowe zwracanie funkcji Nothingnie jest błędem.
Giorgio
@MadScientist: Jeśli wywołanie metody zwraca komunikat „Nieprawidłowa wartość”, instrukcja natychmiast po jej wykonaniu może zostać wykonana. Natomiast jeśli metoda zgłasza wyjątek, który nie jest natychmiast wychwytywany, instrukcja po wywołaniu zostanie pominięta. Pozwalanie, aby sprawdzone wyjątki przenikały przez stos wywołań, jest na ogół złe (i nie powinno być „najłatwiejszym” sposobem radzenia sobie z nimi), ponieważ osoba dzwoniąca nie może stwierdzić, czy warunek ma znaczenie oczekiwane przez wywoływaną metodę, lub czy reprezentuje nieoczekiwany warunek, który wywoływana metoda pozwala na podniesienie poziomu.
supercat