🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: pl.comp.objects
Article #14391

Re: Wyrzucenie wyjątku, czy zwrócenie null?

#14391
From: Przemek Pokrywka
Date: Tue, 28 Mar 2006 21:05
103 lines
5956 bytes
Dziękuję za ciekawą wypowiedź, choć zgadzam się z nią w (mniej więcej) 
połowie

x-plorer napisał(a):
> 1. Już samo określenie wyjątek sugeruje, że chodzi o sytuację rzadko 
> spotykaną. Nieznalezienie obiektu jest w opisanym przypadku równie 
> uprawnione jak jego znalezienie.

Najpierw spróbuję pokazać, że branie określenia "wyjątek" dosłownie może 
nieść za sobą niebezpieczeństwo zignorowania jego istoty jako 
konstrukcji programistycznej.

Choć wprawdzie te dwie sytuacje są równouprawnione, to bywa, że język 
traktuje je nierówno. Przy okazji może wyjść tu moje skażenie Javą i 
przyzwyczajeniem do wyjątków sprawdzanych przez kompilator (AFIK rzadko 
występujących w popularnych językach programowania).
Otóż w wypadku nieodnalezienia obiektu, gdy
a) zwrócony jest null, nic nie powstrzyma roztargnionego programisty 
przed zignorowaniem takiej sytuacji, co najprawdopodobniej zakończy się 
błędem w znacznie dalszej części programu, gdzie znalezienie go nie 
będzie już takie oczywiste.
b) wyrzucony jest wyjątek sprawdzany przez kompilator, błąd kompilacji 
uniemożliwi roztargnionemu programiście przejście dalej

W przypadku wyrzucenia wyjątku programista jest więc wspierany przez 
kompilator w prawidłowej obsłudze wszystkich przypadków.
Owszem, zdarzają się ludzie, którzy po błędzie kompilacji szybko 
dopisują pustą klauzulę catch, ale nie mam takich na myśli.

Następnie chciałbym wykazać, że równouprawnienie dwóch sytuacji nie jest 
wystarczającą przesłanką, żeby nie używać wyjątków.
W aplikacjach, które często operują na plikach na każdym kroku może 
wystąpić sytuacja błędu odczytu/zapisu/nieodnalezienia pliku. Pomimo, że 
zarówno sytuacja odnalezienia pliku, jak i ta przeciwna są 
równouprawnione, zakłada się jednak jakiś podstawowy scenariusz 
działania aplikacji, w którym dobrze wykona ona zadania, do których jest 
przeznaczona. Prawdziwe równouprawnienie przypadków niemal nie występuje 
w praktyce. Przy takich założeniach kod, który w głównym "nurcie" 
rozpatruje te pozytywne przypadki, a w klauzulach obsługi wyjątków 
zajmuje się tymi negatywnymi jest moim zdaniem bardziej czytelny, niż 
kod, który w równouprawnionych gałęziach instrukcji warunkowej 
rozpatruje przypadek podstawowy i alternatywny.
Innymi słowy, użycie instrukcji warunkowej do odróżnienia przypadków 
podstawowego i alternatywnego jest dla mnie "zbyt łaskawym" 
potraktowaniem przypadku alternatywnego.
O prawdziwym równouprawnieniu dwóch przypadków możnaby mówić moim 
zdaniem np. w określaniu płci osoby (i to tylko w aplikacjach, których 
zasadnicze działanie jest niezależnie od tego atrybutu osoby).

> 2. Czytelność kodu. Uważam, że linia postaci:
> 
> if (person == null) // nie znaleziono osoby
> 
> jest bardziej czytelna niż blok chwytania wyjątku.

twierdzę, że od

Person person = find("nemo");
if (person != null)
	process(person);
else
	noPersonFoundCase();

czytelniejsze jest:
try {
	Person person = find("nemo");
	process(person);
catch (PersonNotFoundException e) {
	noPersonFoundCase();
}

dlatego, że w drugim przypadku można w sposób niezakłócony prześledzić 
proces wyszukiwania i przetwarzania obiektu Person z jasno oddzieloną 
obsługą sytuacji wyjątkowej.

> 3. Efektywność. Porównanie z nullem to fizycznie banalne sprawdzenie. 
> Rzucanie i chwytanie wyjątku jest kosztowne. Nie wytaczajmy armaty na 
> wróble.

"Premature optimization is the root of all evil" jak powiedział mistrz 
Knuth - jak zawsze, diabeł tkwi w szczegółach. Rezygnacja z lepszej 
konstrukcji językowej na rzecz niejasnych korzyści wydajnościowych nie 
jest moim zdaniem dobrą praktyką. Jeśli profiling aplikacji wykaże, że 
obsługa wyjątków jest wąskim gardłem, to zgodziłbym się, że w danej 
sytuacji użycie wyjątków może nie być najlepszym wyjściem. Idę jednak o 
zakład, że wyjątki nie stanowią wąskiego gardła w 80% aplikacji.

> Posłużenie się wyjątkiem miałoby wg mnie sens w następującej sytuacji:
> 
> W przebiegu może zajść więcej negatywnych zdarzeń, np. brak uprawnień do 
> danych osoby, dane osoby uniemozliwiają przeprowadzenie dalszych obliczeń 
> (np. obliczenie dni urlopu dla emeryta) itp. W takiej sytuacji można 
> załatwić wszystkie możliwe wyjątki jednym blokiem przechwytywania, pod 
> warunkiem, że ich sposób obsłużenia będzie identyczny niezależnie od typu 
> wyjątku, np. opis wyjątku jest czytelny dla użytkownika i wystarczy 
> wyświetlić go w oknie komunikatu.

Zgadzam się z takim wnioskiem - jednak opisana sytuacja to dla mnie nie 
jest jedyna, w której widziałbym uzasadnienie dla użycia wyjątków.

--
Pozdrawiam,
Przemysław Pokrywka
Technical Details
Message-ID: <e0c8eh$ur8$1@news.onet.pl>
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!mat.uni.torun.pl!news.man.torun.pl!newsfeed.pionier.net.pl!newsfeed.silweb.pl!news.onet.pl!not-for-mail
References: <e09c3r$lg3$1@news.onet.pl> <e09f0h$cis$1@news.task.gda.pl> <e09gjn$737$1@news.onet.pl> <e0b1re$bdc$1@news.onet.pl>

Show Full Headers
Complete Article Headers
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!mat.uni.torun.pl!news.man.torun.pl!newsfeed.pionier.net.pl!newsfeed.silweb.pl!news.onet.pl!not-for-mail
From: Przemek Pokrywka <adres@zastrzezony.com>
Newsgroups: pl.comp.objects
Subject: Re: Wyrzucenie wyjątku, czy
 zwrócenie null?
Date: Tue, 28 Mar 2006 23:05:20 +0200
Organization: Onet.pl
Lines: 103
Message-ID: <e0c8eh$ur8$1@news.onet.pl>
References: <e09c3r$lg3$1@news.onet.pl> <e09f0h$cis$1@news.task.gda.pl> <e09gjn$737$1@news.onet.pl> <e0b1re$bdc$1@news.onet.pl>
NNTP-Posting-Host: 041.inet.polhost.pl
Mime-Version: 1.0
X-Trace: news.onet.pl 1143579921 31592 80.48.120.41 (28 Mar 2006 21:05:21 GMT)
X-Complaints-To: usenet@news.onet.pl
NNTP-Posting-Date: Tue, 28 Mar 2006 21:05:21 +0000 (UTC)
X-Sender: 5aB4pqMdeQG1O30L902dNmlAzoKeNKcS
In-Reply-To: <e0b1re$bdc$1@news.onet.pl>
X-Accept-Language: pl, en-us, en
User-Agent: Mozilla Thunderbird 1.0.2 (Windows/20050317)
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit