Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

try/except/on różne typy wyjątków

107 views
Skip to first unread message

Piotr Rezmer

unread,
Mar 26, 2013, 7:55:57 AM3/26/13
to
Witam,
Znów mam małe zaćmienie. Czy da się w Delphi zrobić obsługe wyjątków na
podobieństwo switch/case czyli

try
...
except
on E:ExceptionA, E:ExceptionB do
handle exception here...
end

zamiast:

try
...
except
on E:ExceptionA, E:ExceptionB do
handle exception here...
on E:ExceptionB do
handle exception here...
end

Chodzi mi o to by w przypadku gdy obsługa dwóch wyjątków jest taka sama,
nie duplikować kodu.


--
pozdrawiam
Piotr
XLR250&bmw_f650_dakar

Tygrys

unread,
Mar 26, 2013, 8:33:03 AM3/26/13
to
W dniu 2013-03-26 12:55, Piotr Rezmer pisze:
Żeby nie duplikować kodu to się procedurę pisze :-)

Arivald

unread,
Mar 26, 2013, 9:00:19 AM3/26/13
to
W dniu 2013-03-26 12:55, Piotr Rezmer pisze:
> Witam,
> Znów mam małe zaćmienie. Czy da się w Delphi zrobić obsługe wyjątków na
> podobieństwo switch/case czyli
>
> try
> ...
> except
> on E:ExceptionA, E:ExceptionB do
> handle exception here...
> end
>
> zamiast:
>
> try
> ...
> except
> on E:ExceptionA, E:ExceptionB do
> handle exception here...
> on E:ExceptionB do
> handle exception here...
> end

Tak to na pewno nie, chociaż by dlatego że używasz "ExceptionB" w obu
sekcjach 'on'. A ze specyfikacji języka wynika że wykonywana jest tlko
jedna sekcja, pierwsza która pasuje.

>
> Chodzi mi o to by w przypadku gdy obsługa dwóch wyjątków jest taka sama,
> nie duplikować kodu.

Możliwości to albo użyć wspólnego przodka dla danej klasy wyjątków,
wtedy robisz sekcję dla tego przodka.

Lub wydelegowanie obsługi wyjątku do funkcji, która już sobie
tradycyjnie rozpozna typ wyjątku.


BTW do procedury obsługi wyjątku niekoniecznie musisz przekazywać
wyjątek, aktualny wyjątek możesz wziąć z System.ExceptObject. Przydaje
się to przy generycznej obsłudze typu:

try
...
except
HandleException(...);
end;

lub:

try
...
except
if not HandleException(...) then raise;
end;

Innym zastosowaniem takiej procedury HandleException() może być zamiana
oryginalnego wyjątku niskopoziomowego na wyjątek biznesowy,
HandleException() może rzucić biznesowym wyjątkiem który poleci dalej
zamiast orginalnego.

Jeszce inne zastosowanie to takie że HandleException() loguje wyjątek,
ale dalej rzuca EAbort (Abort()), czyli wyjątek który zwinie stos, ale
nie będzie skutkował dalszymi komunikatami czy oknem dialogowym.

--
Arivald

Piotr Rezmer

unread,
Mar 26, 2013, 2:29:10 PM3/26/13
to
Arivald pisze:
> W dniu 2013-03-26 12:55, Piotr Rezmer pisze:
>> Witam,
>> Znów mam małe zaćmienie. Czy da się w Delphi zrobić obsługe wyjątków na
>> podobieństwo switch/case czyli
>>
>> try
>> ...
>> except
>> on E:ExceptionA, E:ExceptionB do
>> handle exception here...
>> end
>>
>> zamiast:
>>
>> try
>> ...
>> except
>> on E:ExceptionA, E:ExceptionB do
>> handle exception here...
>> on E:ExceptionB do
>> handle exception here...
>> end
>
> Tak to na pewno nie, chociaż by dlatego że używasz "ExceptionB" w obu
> sekcjach 'on'. A ze specyfikacji języka wynika że wykonywana jest tlko
> jedna sekcja, pierwsza która pasuje.
>
Jasne, tutaj źle skopiowałem fragment kodu

> Możliwości to albo użyć wspólnego przodka dla danej klasy wyjątków,
> wtedy robisz sekcję dla tego przodka.

Akurat w tym przypadku to nie zda egzaminu, bo z wyjątku nadrzędnego
dziedziczy tez inny wyjątek który z kolei wymaga innej obsługi. Ale to
może tez świadczyć o nieodpowiedniej hierarchii wyjątków. W tym
konkretnym przypadku wyjątki generuję przy pobieraniu danych adresowych
klienta. Wyjątkiem nadrzędnym jest coś w stylu EAddressException. Jednak
dziedziczą z niego wyjątki EZipCodeMissingException ( i to wydaje się w
porządku) a także EGetAddressDataException (i to chyba moja pomyłka.
Wyjątki warstwy transportowej powinny być podpięte do innego przodka).

> Lub wydelegowanie obsługi wyjątku do funkcji, która już sobie
> tradycyjnie rozpozna typ wyjątku.
>
Przyznam się że deklaratywne podanie typu obsługiwanego wyjątku jakoś
wydaje mi się bardziej koszerne. Fajnie byłoby też gdyby Delphi
kontrolowało wyjątki wyrzucane przez wszystkie linie kodu metody i
dodawałoby wyjątki do sygnatury metody, a następnie wymuszało użycie
try/except lub dalsze przekazywanie wyjątku tak jak się to odbywa w
Javie. Wtedy trudno przegapić jakieś mniej oczywiste wyjątki.
>
> BTW do procedury obsługi wyjątku niekoniecznie musisz przekazywać
> wyjątek, aktualny wyjątek możesz wziąć z System.ExceptObject. Przydaje
> się to przy generycznej obsłudze typu:
>
> try
> ...
> except
> HandleException(...);
> end;

A to jest zmienna globalna? Co z kodem równoległym? Nie jest jednak
bezpieczniej przekazać E: Exception?

>
> lub:
>
> try
> ...
> except
> if not HandleException(...) then raise;
> end;
>
> Innym zastosowaniem takiej procedury HandleException() może być zamiana
> oryginalnego wyjątku niskopoziomowego na wyjątek biznesowy,
> HandleException() może rzucić biznesowym wyjątkiem który poleci dalej
> zamiast orginalnego.
Z tym że dokładnie to samo można zrobić z klasycznym try/except/on/raise
EAnotherException.Create()
>
> Jeszce inne zastosowanie to takie że HandleException() loguje wyjątek,
> ale dalej rzuca EAbort (Abort()), czyli wyjątek który zwinie stos, ale
> nie będzie skutkował dalszymi komunikatami czy oknem dialogowym.

A jak używam Eurekalog, to czy ma sens używanie handleException() ? W EL
można oczywiście wyłączyć okna dialogowe z wyjątkiem.



--
pozdrawiam
Piotr
XLR250&bmw_f650_dakar

R.e.m.e.K

unread,
Mar 26, 2013, 4:00:29 PM3/26/13
to
Dnia Tue, 26 Mar 2013 19:29:10 +0100, Piotr Rezmer napisał(a):

> Fajnie byłoby też gdyby Delphi
> kontrolowało wyjątki wyrzucane przez wszystkie linie kodu metody i
> dodawałoby wyjątki do sygnatury metody, a następnie wymuszało użycie
> try/except lub dalsze przekazywanie wyjątku tak jak się to odbywa w
> Javie. Wtedy trudno przegapić jakieś mniej oczywiste wyjątki.

Lekko offtopowo spytam, bo juz po raz n-ty wyrazasz zal, ze Delphi to nie
Java, czy przyszedles ze swiata Javy i zmuszony zostales do pisania w
Delphi? Czy tez piszesz od zawsze w Delphi tylko odkryles Jave i
podpatrujesz jej rozwiazania? Pytam z ciekawosci.
Pierwszy przypadek jest mi w pewnym sensie bliski, bo zmigrowalem do Delphi
z Clippera i piewsze co to zrobilem w Delphi kilka unitow posiadajacym
funkcje o sygnaturach Clipperowych ;-)
Drugi przypadek jest bardziej ogolny (czyli chec by Delphi mialo to co inne
powazne jezyki), ale to akurat idzie w dobrym kierunku, wystarczy chocby
porownac Delphi 2005 a XE. Kilka lat roznicy, a w jezyku skok jak nigdy
wczesniej przez dziesieciolecia.

--
pozdro
R.e.m.e.K

Arivald

unread,
Mar 26, 2013, 4:00:00 PM3/26/13
to
W dniu 2013-03-26 19:29, Piotr Rezmer pisze:
Akurat to jest łatwe, ten nadrzędny z inną obsługa umieszczasz jako
pierwszy na liście.

Typowy przykład:

except:
....
on e: EAbort do raise;
on e: Exception do
begin
logger.LogException(e);
Abort();
end;
end;

> Ale to
> może tez świadczyć o nieodpowiedniej hierarchii wyjątków. W tym
> konkretnym przypadku wyjątki generuję przy pobieraniu danych adresowych
> klienta. Wyjątkiem nadrzędnym jest coś w stylu EAddressException. Jednak
> dziedziczą z niego wyjątki EZipCodeMissingException ( i to wydaje się w
> porządku) a także EGetAddressDataException (i to chyba moja pomyłka.
> Wyjątki warstwy transportowej powinny być podpięte do innego przodka).
>

No cóż, dobra hierarchia wyjątków jest dobra ;-)


>> Lub wydelegowanie obsługi wyjątku do funkcji, która już sobie
>> tradycyjnie rozpozna typ wyjątku.
>>
> Przyznam się że deklaratywne podanie typu obsługiwanego wyjątku jakoś
> wydaje mi się bardziej koszerne. Fajnie byłoby też gdyby Delphi
> kontrolowało wyjątki wyrzucane przez wszystkie linie kodu metody i
> dodawałoby wyjątki do sygnatury metody, a następnie wymuszało użycie
> try/except lub dalsze przekazywanie wyjątku tak jak się to odbywa w
> Javie. Wtedy trudno przegapić jakieś mniej oczywiste wyjątki.

Tyle że ten mechanizm w Javie jest jak miecz obosieczny: często
deklaruje się funkcje rzucają generyczny 'Exception', co potem jes mało
użyteczne, a bywa uciążliwe.

>>
>> BTW do procedury obsługi wyjątku niekoniecznie musisz przekazywać
>> wyjątek, aktualny wyjątek możesz wziąć z System.ExceptObject. Przydaje
>> się to przy generycznej obsłudze typu:
>>
>> try
>> ...
>> except
>> HandleException(...);
>> end;
>
> A to jest zmienna globalna? Co z kodem równoległym? Nie jest jednak
> bezpieczniej przekazać E: Exception?
>

To jest funkcja. Zwraca aktualny wyjątek ze stosu wyjątków
(implementowany jako linked-list). A wskaźnik na stos jest w TLS
(thread-local storage), więc każdy wątek ma swój stos.

Jak bardzo chcesz to można sobie spokojnie w każdym momencie sczytać
cały stos wyjątków, razem z innymi danymi, np. adresami ich wystąpienia.

"E: Exception" jest łatwiejsze, ale nie zawsze dostępne, np
Application.HandleException() go nie dostaje.


>>
>> lub:
>>
>> try
>> ...
>> except
>> if not HandleException(...) then raise;
>> end;
>>
>> Innym zastosowaniem takiej procedury HandleException() może być zamiana
>> oryginalnego wyjątku niskopoziomowego na wyjątek biznesowy,
>> HandleException() może rzucić biznesowym wyjątkiem który poleci dalej
>> zamiast orginalnego.
> Z tym że dokładnie to samo można zrobić z klasycznym try/except/on/raise
> EAnotherException.Create()

Można.
Tyle że ogólne handlery, takie jak Application.HandleException(), czy
moje TAThread.HandleException() zazwyczaj nie mają takiego luksusu.

Po drugie rzuconym obiektem wcale nie musi być coś dziedziczącego po
Exception. A wtedy tradycyjne on 'E: Exception do' nie wyłapie wyjątku.


Zresztą nie traktuj moich słów jak ewangelii, że tak koniecznie trzeba
;-) Po prostu pokazuję możliwości.

Kolejna możliwość rozwiązania Twojego problemu:

except
on E: Exception do
begin
if E is EIOError then
....
else
if (E is EBusinessError) and Assigned(FOnError) then
FOnError(Self, E as EBusinessError)
else
Application.HandleException(Self);
end;
end;


>>
>> Jeszce inne zastosowanie to takie że HandleException() loguje wyjątek,
>> ale dalej rzuca EAbort (Abort()), czyli wyjątek który zwinie stos, ale
>> nie będzie skutkował dalszymi komunikatami czy oknem dialogowym.
>
> A jak używam Eurekalog, to czy ma sens używanie handleException() ? W EL
> można oczywiście wyłączyć okna dialogowe z wyjątkiem.

Nie wiem co robi EL, pewni tylko loguje wyjątek. Jeśli taka obsługa Ci
wystarczy, to czemu nie.
Ale logowanie nie zawsze wystarcza...

Zresztą EL pewnie podłącza się do Application.OnException, co działa
dobrze, ale tyko dla VCL, i kodu który używa Application.HandleException().

--
Arivald


Krzysztof Szyszka

unread,
Mar 27, 2013, 2:46:46 AM3/27/13
to
> Fajnie byłoby też gdyby Delphi kontrolowało wyjątki wyrzucane przez wszystkie linie kodu metody i
> dodawałoby wyjątki do sygnatury metody, a następnie wymuszało użycie try/except lub dalsze
> przekazywanie wyjątku tak jak się to odbywa w Javie. Wtedy trudno przegapić jakieś mniej oczywiste
> wyjątki.

A ja chyba nie rozumiem tego, co tu napisałeś?

Czy ty chcesz, żeby po pierwszym wyjątku w danej metodzie program
"szedł" sobie dalej jakby nigdy nic do końca metody i wyłapywał kolejne
wyjątki w kolejnych liniach kodu tej metody ?

--
pozdrowienia
Krzysztof Szyszka, X-Files Software
Developer of X-DBGrid Component
Embarcadero Technology Partner
http://www.x-files.pl/

Arivald

unread,
Mar 27, 2013, 3:11:24 AM3/27/13
to
W dniu 2013-03-27 07:46, Krzysztof Szyszka pisze:
>> Fajnie byłoby też gdyby Delphi kontrolowało wyjątki wyrzucane przez
>> wszystkie linie kodu metody i dodawałoby wyjątki do sygnatury metody,
>> a następnie wymuszało użycie try/except lub dalsze przekazywanie
>> wyjątku tak jak się to odbywa w Javie. Wtedy trudno przegapić jakieś
>> mniej oczywiste wyjątki.
>
> A ja chyba nie rozumiem tego, co tu napisałeś?
>
> Czy ty chcesz, żeby po pierwszym wyjątku w danej metodzie program
> "szedł" sobie dalej jakby nigdy nic do końca metody i wyłapywał kolejne
> wyjątki w kolejnych liniach kodu tej metody ?
>

No nie zrozumiałeś ;-)

Chodziło o to aby lista wszystkich wyjątków jakie może rzucić
funkcja/procedura była elementem sygnatury funkcji/procedury. Ale
"wszystkich" oznacza że jak na liście dasz typ bazowy wyjątku, to
obejmuje to wszystkie jego typy potomne.

I teraz mając listę wyjątków rzucanych dla każdej funkcji, oraz listy
wyjątków rzucanych i obsługiwanych wewnątrz funkcji, kompilator pilnuje
aby dla każdej funkcji każdy wyjątek który jest w stanie opuścić funkcję
znalazł się na jej liście wyjątków.

To znaczy że jak funkcja A woła funkcję B, a B zgłasza że rzuca
wyjątkiem E, to funkcja A albo musi obsłużyć wyjątek E (otoczyć
wywołanie B try/except on e:E ...), albo dodać wyjątek E do swojej listy.


W Javie to działa od początku, kod się dostosował.

W Delphi było by z tym pełno kłopotu, np każdy Event handler musiał by
zgłaszać rzucanie najbardziej podstawowego typy wyjątku (Exception), bo
za cholerę nie wiadomo jakie wyjątki może rzucić kod usera w handlerze.

W Javie na przykład nie ma czegoś takiego jak Event z VCL czy po prostu
callback, więc nie ma takiego problemu.

--
Arivald

Piotr Rezmer

unread,
Mar 27, 2013, 4:32:19 AM3/27/13
to
R.e.m.e.K pisze:
avie. Wtedy trudno przegapić jakieś mniej oczywiste wyjątki.
>
> Lekko offtopowo spytam, bo juz po raz n-ty wyrazasz zal, ze Delphi to nie
> Java, czy przyszedles ze swiata Javy i zmuszony zostales do pisania w
> Delphi? Czy tez piszesz od zawsze w Delphi tylko odkryles Jave i
> podpatrujesz jej rozwiazania? Pytam z ciekawosci.

Rys historyczny:
Lata 80: Basic, pierwsza "klawiatura" z bloku technicznego na której
uczyłem się skrótów klawiaturowych. Samego ZX Spectrum nie posiadałem -
był tylko w strefie marzeń
Lata 90: Pascal, pierwsze komputery na uczelni, działające na systemie
CP/M. Następnie pierwsze komputery IBM PC/XT i AT (u kolegów w
akademiku), na których korzystałem z dziecka Borlanda czyli Turbo
Pascal. Dalej własny PC/AT 286+287. Przyszła kolej na języki chyba już
4GL czyli środowisko dBase III/ IV. Kolejny krok, już prawie
"profesjonalizm" czyli programy .EXE generowane przez Clippera. W tym
języku zrobiłem bibliotekę GUI która miała być odpowiednikiem okienek w
Turbo Pascal. Dalej, pojawia się Windows 95 i piszę pierwsze programy w
microsoftowym basicu wewnątrz Office'a czyli w MS Access i MS Excel.
Zdaje się że robiłem też jakieś drobne rzeczy w MS Word.
Lata 20??: Kolega pokazuje mi Delphi 3. Jestem zafascynowany znakomitym
jak na tamte czasy środowiskiem, łatwością budowania GUI. Delphi staje
się moim głównym narzędziem. W międzyczasie pojawia się Java. Na
początku nie dorównuje szybkością Delphi, GUI aplikacji w javie jest
toporne. Jedyny plus - przenośność. Czas leci, Delphi rozwija się bardzo
powoli, java bardzo szybko. Gdzieś od wersji 1.5 poczułem że język javy
jest przyjemniejszy, a otoczenie języka (biblioteki, narzędzia) stawiają
go w tej chwili na pierwszym miejscu w mojej hierarchii, jeśli mam
wybierać środowisko do implementacji usług.
W międzyczasie pojawił się jeszcze .NET. Jednak nie przekonuje mnie do
siebie np. jeśli chodzi o WebForms - dla mnie proteza, nad którą
użytkownik nie ma pełnej kontroli. Lepiej jest w WinForms - zwłaszcza że
biblioteki GUI 3rd party są w tej chwili głównie ukierunkowane na .NET,
zaś VCL jest chyba traktowany jako spuścizna do podtrzymania.




--
pozdrawiam
Piotr
XLR250&bmw_f650_dakar

Krzysztof Szyszka

unread,
Mar 27, 2013, 4:33:04 AM3/27/13
to
Przecież tu nawet nie chodzi o eventy. Skąd taka metoda jak np. DataSet.Open
ma wiedzieć, jakie wyjątki mogą zostać zgłoszone, skoro ona nawet nie wie,
z jakim DAC ma do czynienia. To są zupełne mrzonki, a ewentualna lista
możliwych wyjątków byłaby dłuższa niż sam program ;-)

Piotr Rezmer

unread,
Mar 27, 2013, 5:24:50 AM3/27/13
to
Krzysztof Szyszka pisze:

> ma wiedzieć, jakie wyjątki mogą zostać zgłoszone, skoro ona nawet nie wie,
> z jakim DAC ma do czynienia. To są zupełne mrzonki, a ewentualna lista
> możliwych wyjątków byłaby dłuższa niż sam program ;-)

Ee, zwykle nie jest tak źle z ilością wyjątków. Przecież nie wszystkie
propagujesz do warstw wyższych. A to, jakie wyjątki może generować
provider jest określone w metodach interfejsu który implementuje. Dla
mnie takie podejście jest OK, programista wie na co może sobie pozwolić
podczas implementacji, a co musi samodzielnie obsłużyć. Taki kierat jest
dobry.

Moim zdaniem takie podejście jest lepsze od samowolki, gdyż łatwiej
zorientować się czy obsłużyłeś wszystkie możliwe "nieszczęścia" które
mogą wystąpić w trakcie działania programu.

PS: Do samowolki w Javie jest coś takiego jak RuntimeException. Nie
trzeba takich wyjątków deklarować w sygnaturze metody.



--
pozdrawiam
Piotr
XLR250&bmw_f650_dakar

Krzysztof Szyszka

unread,
Mar 27, 2013, 6:01:23 AM3/27/13
to
> > ma wiedzieć, jakie wyjątki mogą zostać zgłoszone, skoro ona nawet nie wie,
> > z jakim DAC ma do czynienia. To są zupełne mrzonki, a ewentualna lista
> > możliwych wyjątków byłaby dłuższa niż sam program ;-)
>
> Ee, zwykle nie jest tak źle z ilością wyjątków. Przecież nie wszystkie propagujesz do warstw
> wyższych. A to, jakie wyjątki może generować provider jest określone w metodach interfejsu który
> implementuje. Dla mnie takie podejście jest OK, programista wie na co może sobie pozwolić podczas
> implementacji, a co musi samodzielnie obsłużyć. Taki kierat jest dobry.
>
> Moim zdaniem takie podejście jest lepsze od samowolki, gdyż łatwiej zorientować się czy obsłużyłeś
> wszystkie możliwe "nieszczęścia" które mogą wystąpić w trakcie działania programu.

Twój problem polega na tym, że ty wyjątki traktujesz jak "nieszczęścia",
a w Delphi jest to jeden z elementów sterowania przebiegiem programu.

W dobrze napisanym programie jest naprawdę bardzo niewiele takich
miejsc, gdzie koniecznie trzeba użyć klauzuli try except end, za to jest
(powinno być) wiele bloków try finally end, żeby program nie musiał się
martwić o te, jak piszesz "nieszczęścia". Zazwyczaj naprawdę niewiele
mnie interesuje, jaki rodzaj wyjątku został zgłoszony gdzieś głębiej,
natomiast istotna jest sama informacja, że czegoś nie udało się zrobić
i to wystarcza do odpowiedniego sterowania przebiegiem programu.

Obsługą tych "nieszczęść" niech zajmie się użytkownik, jeśli potrafi,
bo to zazwyczaj on jest ich przyczyną (np. wprowadził złe dane). Ja
zajmuję się tylko tymi wyjątkami, których się spodziewam i potrafię
na danym etapie naprawić, a takich zazwyczaj jest niewiele i żadna
lista nie jest mi do tego potrzebna, bo pisząc osobny kod obsługi
wyjątku, sam muszę wiedzieć, co poprawiam i dlaczego.

Im szybciej to zrozumiesz, tym szybciej się do wyjątków przekonasz.
Już wiele razy o tym pisałem (i Arivald też).

darekm

unread,
Mar 27, 2013, 8:18:07 AM3/27/13
to
W dniu 2013-03-27 11:01, Krzysztof Szyszka pisze:
>> > ma wiedzieć, jakie wyjątki mogą zostać zgłoszone, skoro ona nawet
>> nie wie,
>> > z jakim DAC ma do czynienia. To są zupełne mrzonki, a ewentualna lista
>> > możliwych wyjątków byłaby dłuższa niż sam program ;-)
>>
>> Ee, zwykle nie jest tak źle z ilością wyjątków. Przecież nie wszystkie
>> propagujesz do warstw wyższych. A to, jakie wyjątki może generować
>> provider jest określone w metodach interfejsu który implementuje. Dla
>> mnie takie podejście jest OK, programista wie na co może sobie
>> pozwolić podczas implementacji, a co musi samodzielnie obsłużyć. Taki
>> kierat jest dobry.
>>
>> Moim zdaniem takie podejście jest lepsze od samowolki, gdyż łatwiej
>> zorientować się czy obsłużyłeś wszystkie możliwe "nieszczęścia" które
>> mogą wystąpić w trakcie działania programu.
>
> Twój problem polega na tym, że ty wyjątki traktujesz jak "nieszczęścia",
> a w Delphi jest to jeden z elementów sterowania przebiegiem programu.
>
> W dobrze napisanym programie jest naprawdę bardzo niewiele takich
> miejsc, gdzie koniecznie trzeba użyć klauzuli try except end, za to jest
> (powinno być) wiele bloków try finally end, żeby program nie musiał się
> martwić o te, jak piszesz "nieszczęścia". Zazwyczaj naprawdę niewiele
> mnie interesuje, jaki rodzaj wyjątku został zgłoszony gdzieś głębiej,
> natomiast istotna jest sama informacja, że czegoś nie udało się zrobić
> i to wystarcza do odpowiedniego sterowania przebiegiem programu.
>

Trochę przeczysz sam sobie. Jeżeli wyjątek ma być elementem sterowania
przebiegiem programu to właśnie program winien rozróżniać rodzaje
wyjątków i na tej podstawie sterować przebiegiem. Jeżeli robisz to w
niewielu miejscach to w niewielkim stopniu wykorzystujesz wyjątki do
sterowania.


> Obsługą tych "nieszczęść" niech zajmie się użytkownik, jeśli potrafi,
> bo to zazwyczaj on jest ich przyczyną (np. wprowadził złe dane). Ja
> zajmuję się tylko tymi wyjątkami, których się spodziewam i potrafię
> na danym etapie naprawić, a takich zazwyczaj jest niewiele i żadna
> lista nie jest mi do tego potrzebna, bo pisząc osobny kod obsługi
> wyjątku, sam muszę wiedzieć, co poprawiam i dlaczego.
>

Mówisz o sterowaniu a każdy przykład dotyczy sytuacji awaryjnej.
Pokazywanie wyjątku userowi nie jest właściwe, user powinien otrzymać
komunikat albo powinien być zapis do logu albo powinno zostać wykonane
inne działanie. Skrót myślowy: wyjątek - > spodziewany: to naprawiam
->inny: pokażę userowi prowadzi właśnie do traktowania wyjątków jako
nieszczęść.




--
Darek



Piotr Rezmer

unread,
Mar 27, 2013, 9:08:39 AM3/27/13
to
Krzysztof Szyszka pisze:

> Twój problem polega na tym, że ty wyjątki traktujesz jak "nieszczęścia",
> a w Delphi jest to jeden z elementów sterowania przebiegiem programu.

Specjalnie użyłem cudzysłowowa aby przekazać że to na niby. Być może nie
udało mi się dokładnie przekazać tego co mam na myśli. Dla mnie wyjątek
to sposób na zasygnalizowanie że proces nie poszedł zgodnie ze
standardową ścieżką. Absolutnie nie chodzi mi o to by stłamsić wyjątki
za pomocą try/except. Wyjątki rzucam samodzielnie gdy nie chcę brać
odpowiedzialności za decyzję co robić dalej. Dotyczy to zwłaszcza
współdzielonych bibliotek gdzie taka decyzja zależy od konkretnego
przypadku.

--
pozdrawiam
Piotr
XLR250&bmw_f650_dakar

Krzysztof Szyszka

unread,
Mar 27, 2013, 10:10:38 AM3/27/13
to
> Trochę przeczysz sam sobie. Jeżeli wyjątek ma być elementem sterowania przebiegiem programu to
> właśnie program winien rozróżniać rodzaje wyjątków i na tej podstawie sterować przebiegiem. Jeżeli
> robisz to w niewielu miejscach to w niewielkim stopniu wykorzystujesz wyjątki do sterowania.

Ależ skąd. Sterujesz tam gdzie musisz, albo tam, gdzie możesz zamienić
ścieżkę awaryjną (wyjątek) na ścieżkę normalną lub inny wyjątek, a nie
a tam, gdzie się go da wyłapać.

> > Obsługą tych "nieszczęść" niech zajmie się użytkownik, jeśli potrafi,
> > bo to zazwyczaj on jest ich przyczyną (np. wprowadził złe dane). Ja
> > zajmuję się tylko tymi wyjątkami, których się spodziewam i potrafię
> > na danym etapie naprawić, a takich zazwyczaj jest niewiele i żadna
> > lista nie jest mi do tego potrzebna, bo pisząc osobny kod obsługi
> > wyjątku, sam muszę wiedzieć, co poprawiam i dlaczego.
>
> Mówisz o sterowaniu a każdy przykład dotyczy sytuacji awaryjnej. Pokazywanie wyjątku userowi nie
> jest właściwe, user powinien otrzymać komunikat albo powinien być zapis do logu albo powinno
> zostać wykonane inne działanie. Skrót myślowy: wyjątek - > spodziewany: to naprawiam ->inny:
> pokażę userowi prowadzi właśnie do traktowania wyjątków jako nieszczęść.

Przecież ja Ci nie mówię, że masz go pokazać w stanie surowym, ale od tego
jest Application.HandleExcepction, żebyś się mógł tym zająć w jednym miejscu
i tam sobie decyduj, co idzie do loga, a co musi zobaczyć użytkownik i w jakiej
postaci. Możesz mu nawet filmik pokazać co zrobił źle, jak masz taką ochotę,
ale to już nie ma żadnego wpływu na sterowanie przebiegiem programu.

Obsługa wyjątków w kodzie procedur ma sens wtedy, gdy jesteś w stanie
coś zmienić/naprawić, ale żeby to zrobić, to musisz napisać specjalny kod,
który naprawi konkretne błędy, a wszystkie wyjątki na raz.

darekm

unread,
Mar 27, 2013, 11:20:39 AM3/27/13
to
W dniu 2013-03-27 15:10, Krzysztof Szyszka pisze:
>> Trochę przeczysz sam sobie. Jeżeli wyjątek ma być elementem sterowania
>> przebiegiem programu to właśnie program winien rozróżniać rodzaje
>> wyjątków i na tej podstawie sterować przebiegiem. Jeżeli robisz to w
>> niewielu miejscach to w niewielkim stopniu wykorzystujesz wyjątki do
>> sterowania.
>
> Ależ skąd. Sterujesz tam gdzie musisz, albo tam, gdzie możesz zamienić
> ścieżkę awaryjną (wyjątek) na ścieżkę normalną lub inny wyjątek, a nie
> a tam, gdzie się go da wyłapać.

No to chyba mamy inną definicję sterowania. Jeżeli robisz coś w niewielu
miejscach to dla mnie w niewielu miejscach podejmujesz decyzję
sterowania programem, jak nie rozróżniasz wyjątków (cytat "Zazwyczaj
naprawdę niewiele mnie interesuje, jaki rodzaj wyjątku został
zgłoszony") to zazwyczaj nie sterujesz tylko właśnie " traktujesz
wyjątek jak "nieszczęścia"" o których należy powiadomić usera.
Przy czym nie mówię że tak robisz, tylko że tak wynika z tego co
powiedziałeś.

Dla mnie wyjątek to nie tylko informacja o nietypowym zdarzeniu, ale
również narzędzie umożliwiające: przeskok wielu poziomów wywołanych
podprocedur jak również zdefiniowanie funkcji z "drugim punktem
wyjścia". Na tej podstawie mogę sterować przebiegiem programu. Coś na
zasadzie instrukcji warunkowej specjalnego przeznaczenia.
Przykłady takich wyjątków : Nie znaleziono, Nacisnięto ESC, User wybrał QUIT

>
>> > Obsługą tych "nieszczęść" niech zajmie się użytkownik, jeśli potrafi,
>> > bo to zazwyczaj on jest ich przyczyną (np. wprowadził złe dane). Ja
>> > zajmuję się tylko tymi wyjątkami, których się spodziewam i potrafię
>> > na danym etapie naprawić, a takich zazwyczaj jest niewiele i żadna
>> > lista nie jest mi do tego potrzebna, bo pisząc osobny kod obsługi
>> > wyjątku, sam muszę wiedzieć, co poprawiam i dlaczego.
>>
>> Mówisz o sterowaniu a każdy przykład dotyczy sytuacji awaryjnej.
>> Pokazywanie wyjątku userowi nie jest właściwe, user powinien otrzymać
>> komunikat albo powinien być zapis do logu albo powinno zostać wykonane
>> inne działanie. Skrót myślowy: wyjątek - > spodziewany: to naprawiam
>> ->inny: pokażę userowi prowadzi właśnie do traktowania wyjątków jako
>> nieszczęść.
>
> Przecież ja Ci nie mówię, że masz go pokazać w stanie surowym, ale od tego
> jest Application.HandleExcepction, żebyś się mógł tym zająć w jednym
> miejscu

no właśnie nie, a w zasadzie nie tylko. Nie wszystkie wszystkie
wyjątki, szczególnie te, które nie zanamionują sytuacji awaryjnej
dolatują do Application.handleException.

> i tam sobie decyduj, co idzie do loga, a co musi zobaczyć użytkownik i w
> jakiej
> postaci. Możesz mu nawet filmik pokazać co zrobił źle, jak masz taką
> ochotę,
> ale to już nie ma żadnego wpływu na sterowanie przebiegiem programu.

Jak to nie. Jeżeli na podstawie otrzymanego wyjątku podejmuję taką a nie
inną akcję, to to właśnie jest sterowanie.

>
> Obsługa wyjątków w kodzie procedur ma sens wtedy, gdy jesteś w stanie
> coś zmienić/naprawić, ale żeby to zrobić, to musisz napisać specjalny kod,
> który naprawi konkretne błędy, a wszystkie wyjątki na raz.
>

Jeżeli mam coś naprawić to wyjątek sugeruje "nieszczęście" a pisałeś że
to nie tylko do takich przypadków służy. Reszty zdania nie rozumiem.


--
Darek



Krzysztof Szyszka

unread,
Mar 27, 2013, 1:21:37 PM3/27/13
to
> >> Trochę przeczysz sam sobie. Jeżeli wyjątek ma być elementem sterowania
> >> przebiegiem programu to właśnie program winien rozróżniać rodzaje
> >> wyjątków i na tej podstawie sterować przebiegiem. Jeżeli robisz to w
> >> niewielu miejscach to w niewielkim stopniu wykorzystujesz wyjątki do
> >> sterowania.
> >
> > Ależ skąd. Sterujesz tam gdzie musisz, albo tam, gdzie możesz zamienić
> > ścieżkę awaryjną (wyjątek) na ścieżkę normalną lub inny wyjątek, a nie
> > a tam, gdzie się go da wyłapać.
>
> No to chyba mamy inną definicję sterowania. Jeżeli robisz coś w niewielu miejscach to dla mnie w
> niewielu miejscach podejmujesz decyzję sterowania programem, jak nie rozróżniasz wyjątków (cytat
> "Zazwyczaj naprawdę niewiele mnie interesuje, jaki rodzaj wyjątku został zgłoszony") to zazwyczaj
> nie sterujesz tylko właśnie " traktujesz wyjątek jak "nieszczęścia"" o których należy powiadomić
> usera.
> Przy czym nie mówię że tak robisz, tylko że tak wynika z tego co powiedziałeś.

Cały czas nie rozumiesz, że do prawidłowego sterowania przebiegiem
programu ZAZWYCZAJ nie jest mi potrzebna wiedza o tym, jaki KONKRETNY
wyjątek został zgłoszony. Do sterowania programem ZAZWYCZAJ wystarcza
mi samo WYSTĄPIENIE WYJĄTKU. Jeśli w jakiejś procedurze mam otworzyć
DataSet i dostaję wyjątek przy Open, to NA TYM ETAPIE nie muszę wiedzieć
KONRETNIE, czemu to się nie udało, bo i tak taka wiedza nic mi TUTAJ nie daje.
Pozostaje mi tylko posprzątać, jeśli jest taka potrzeba i robię to w try finally end.

> > Przecież ja Ci nie mówię, że masz go pokazać w stanie surowym, ale od tego
> > jest Application.HandleExcepction, żebyś się mógł tym zająć w jednym miejscu
>
> no właśnie nie, a w zasadzie nie tylko. Nie wszystkie wszystkie wyjątki, szczególnie te, które
> nie zanamionują sytuacji awaryjnej dolatują do Application.handleException.

To oczywiste. Skoro zostały gdzieś po drodze obsłużone i zgaszone, to już
nie są wyjątkami, więc po co miałbym się nimi zajmować.

> > Obsługa wyjątków w kodzie procedur ma sens wtedy, gdy jesteś w stanie
> > coś zmienić/naprawić, ale żeby to zrobić, to musisz napisać specjalny kod,
> > który naprawi konkretne błędy, a nie wszystkie wyjątki na raz.
>
> Jeżeli mam coś naprawić to wyjątek sugeruje "nieszczęście" a pisałeś że to nie tylko do takich
> przypadków służy. Reszty zdania nie rozumiem.

Definicja moich pojęć :-)
Obsługa wyjątków - try except end
Jesteś w stanie - wiesz jaki w tym miejscu napisać kod
Zmienić - wykonać inną akcję w razie wystąpienia wyjątku
Naprawić - zgasić wyjątek i kontynuować dalszą pracę mimo wystąpienia wyjątku

Piotr Rezmer

unread,
Mar 28, 2013, 2:28:20 AM3/28/13
to
Krzysztof Szyszka pisze:

>
> Cały czas nie rozumiesz, że do prawidłowego sterowania przebiegiem
> programu ZAZWYCZAJ nie jest mi potrzebna wiedza o tym, jaki KONKRETNY
> wyjątek został zgłoszony. Do sterowania programem ZAZWYCZAJ wystarcza
> mi samo WYSTĄPIENIE WYJĄTKU. Jeśli w jakiejś procedurze mam otworzyć
> DataSet i dostaję wyjątek przy Open, to NA TYM ETAPIE nie muszę wiedzieć
> KONRETNIE, czemu to się nie udało, bo i tak taka wiedza nic mi TUTAJ nie
> daje.

Moim zdaniem to że ZAZWYCZAJ nie potrzebujesz wiedzy o wyjątku wynika z
tego, że pracujesz głównie nad kodem kontrolek DB. Tam się nie używa
wyjątków biznesowych bo w tej warstwie aplikacji nie używa się jeszcze
obiektów biznesowych. Jeśli jednak pisałbyś kod warstwy biznesowej, to
pojawiają się tam wyjątki nie związane z Dataset.Open() ale generowane
np na podstawie zawartości danych (np. brak środków na koncie). W takiej
sytuacji potrzebujesz informacji o tym jaki to był wyjątek.


--
pozdrawiam
Piotr
XLR250&bmw_f650_dakar

PaSkol

unread,
Mar 28, 2013, 3:35:48 AM3/28/13
to
W dniu 2013-03-28 07:28, Piotr Rezmer pisze:
Ale Krzysztof dokładnie o tym pisze. W ciągu wywołań, istnieje taki jego
obszar, który nie interpretuje wyjątków, jedynie zauważa, że wystąpiła
sytuacja wyjątkowa, zatem należy sprawić, aby nie wpłynęła ona
negatywnie na to, co dane "wywołanie" realizuje. Najprostszym przykładem
jest wyciek pamięci (stąd owe "finally", które ma posprzątać).

Istnieje także taki obszar w ciągu wywołań, który wyjątki zaczyna
interpretować. Sam piszesz o "wyjątkach biznesowych" i to właśnie w
warstwie "biznesowej" jest sens interpretowania wyjątków. Można je
zastąpić bardziej specjalizowanymi i puścić dalej, albo zapobiec ich
skutkom (ot choćby poprzez zwiększenie timeoutu i ponowne wykonanie
polecenia).

Sądzę zresztą, że obaj wiecie o co chodzi, tylko każdy opisuje to z
innego punktu widzenia. A osąd ten opieram na tym, że pamiętam Twoje
wcześniejsze wypowiedzi na temat wyjątków, przepływu sterowania, itd.

Podejrzewam też, że Krzysztof miał na myśli zbyt wczesne zastępowanie
wyjątków jakimś innym mechanizmem, zamiast zezwolenia im na propagowanie
się do właściwego miejsca ich interpretacji. To jest częsty błąd,
łapanie wyjątku i sterowanie programem w zupełnie inny sposób -
chociażby wynik funkcji - coś co wyjątki miały wyrugować.

Mam w potworku, który muszę utrzymywać, właśnie takie przykłady, kiedy
podczas otwierania DataSeta jest cała banda interpretacji wyjątków w
sekcji exception i (sic!) wywoływanie warstwy dialogu z użytkownikiem.
No po prostu przepięknie to rozp...ala całą aplikację.

--
Dearth PaSkol (paskol.robi.to)

- Ciemna druga strona jest.
- Nie marudź Yoda, tylko jedz tego tosta.

Krzysztof Szyszka

unread,
Mar 28, 2013, 5:47:52 AM3/28/13
to
Ale te zasady, które podaje wystarczy stosować W KAŻDEJ warstwie, bo są
uniwersalne. Jeżeli metoda X miała wysłać przelew z Konta Y i dostałeś
wyjątek o braku środków na koncie Y, to przecież metoda X nie wie o tym,
co masz zrobić w takim przypadku, ale gdzieś wyżej masz zapisane w
regułach biznesowych, że wtedy należy posłać przelew z konta Z i wtedy
tam gdzieś wyżej zostanie ponownie wykonana metoda X w ramach obsługi
tego wyjątku, tylko już z innym numerem konta w parametrze.

A jeśli nigdzie wyżej nie zostanie to obsłużone, to wyjątek powinien trafić
do Application.HandleException, bo to oznacza lukę w regułach biznesowych,
i trzeba pozwolić użytkownikowi podjąć decyzję, co wtedy zrobić, a nie
prowadzić z użytkownikiem dialogu po wystąpieniu wyjątku w metodzie X.

Pisząc metodę X do wysyłania przelewów zupełnie mnie nie interesuje
Z JAKIEGO POWODU nie udało się tego przelewu wykonać. Zresztą PaSKol
bardzo dobrze zinterpretował moje wypowiedzi, więc nie chcę się dalej rozpisywać.
0 new messages