Article

From:
To:
Kristofer Skaug
Subject:
Re: Exceptions vs Error codes
Newsgroup:
borland.public.delphi.objectpascal

Re: Exceptions vs Error codes

In article <3b7fb52a_1@dnews>
	"Kristofer Skaug" <✉skaug.demon.nl> wrote:

> "Barry Kelly" <✉eircom.net> wrote in message
> news:✉4ax.com...
>
> > > It *is* a virtue to survive errors.
> >
> > If they weren't exceptions, and were error codes instead,
> > and you didn't treat them as seriously as you must 
> > exceptions, then you wouldn't be surviving errors - 
> > you'd be ignoring them.
> 
> there are lots of 'ifs' in that statement.

No there aren't. You show me where the reasoning breaks down:

* You can ignore error codes in your code and your code   will continue blithely onwards to the next statement -   this doesn't happen with exceptions. * If you consider this behaviour to be a downpoint of   exceptions, then you must see virtue in ignoring error   conditions. * If you see virtue in ignoring error conditions, you   aren't surviving errors - you are ignoring them.   (this point follows directly)
> > [...]
> Stay tuned...! <g>

I'm more convinced than ever! <g>

> > 1) Faulty input - alert the user.
> 
> ok, but I don't see input errors as faults; 
> failure *due to* input error is a fault 

I ask for an integer. The user enters "x". 

* Does my StrToInt routine have a fault for not converting it?
or
* Is the input faulty?
I fear we're losing the semantics here; we need to define "failure", "fault" and responsibility for input and correction more clearly in order to say what's best for each case.
> (a decent program should be immune to input errors, i.e. not
> fall over because of it).

And raising an exception which subsequently gets shown 
to the user isn't falling over.

"'x' isn't a valid integer value" or something to that effect.
> > 2) Faulty programming - a bug; fixing the bug should be more important
> >    than a band-aid.
> 
> yes, you want to fix the bug.
> but it is too late and may have caused irreparable damage when it happens
> the first time.
> especially if the means of exposing/publicising the error participates in
> aggravating the consequences.

I have an editor. It's called PFE - Programmer's File Editor. It's at
version 1.01.000, and the author says he's not going to update it any
more.

One day, I opened a Pascal file in it for a quick edit and compile on the command line. It looked fine in the editor. It looked fine when I edited it. It looked fine when I saved it. It looked fine.
I tried to compile it. I got some gibberish from dcc32 about some syntax error. So, I opened the file up again.
The file was a mass of binary characters.
Now, you can say what you like, but that editor continuing and surviving long enough to save its "buffer" to disk was *lethal*. The sooner it could have crashed and alerted me, the better.
I just don't believe in what you're advocating. Don't mind that it isn't a good idea; it isn't even ethical.
> > But what about when you finally decide you can't deal with this
> problem,
> > and you must pass it up to your most senior transaction, and say "I
> > can't do this Boss". He might have to say the same to his boss too;
> this
> > is what exceptions are for. They pass the same / extended letter of
> > failure around so that if the whole process ultimately fails, because
> > the workarounds weren't clever enough, there'll be some documentation
> > that can be placed in the lap of some human somewhere sometime.
> >
> > Error codes can make this very messy; other approaches pass logging
> > objects around. I think exceptions are neater than either.
> 
> No it's not really that messy. For example, the way I ususally do this
> is:

This code:

* Loses the concept of natural return value (that is, every   function is effectively a procedure since the return value   has been hijacked for another purpose.
* Requires plumbing in *every* procedure, even if it doesn't have to   do any error management itself.
* Is trying to reinvent exceptions, but maybe you don't know that yet.
* Requires now partially redundant try..finally blocks for cleanup.
> function BigBoss():TErrorInfo;
> var MidError:TErrorInfo;
> begin
>    MidError:=MiddleManager();
>    Result:=f(MidError);
> end;
> [...]
> function JuniorEngineer():TErrorInfo;
> var LowError:TErrorInfo;
> begin
>    try
>       LowError:= SomelowlevelAPI;
>    except
>       LowError:=ERR_API_EXCEPTION;
>    end;
>    Result:=f(LowError);
> end;
> 
> Furthermore, at each level the function can signal error info to the user
> interface if deemed necessary.

I wouldn't dream of letting *my* back end near the user interface. <g>

> Also, the error information is abstracted to an appropriate level in each
> step; for example, BigBoss() cannot use any information about
> ERR_API_EXCEPTION, it has no idea what that means. The only language
> BigBoss understands is MiddleManager saying "We have technical
> difficulties, and have taken steps to fix them". BigBoss on his side
> concludes that "we'll have a 2 week project slip and $180,000 lost
> profit".  Of course, all JuniorEngineer() is able to say is
> "SomeLowLevelAPI failed with error code -18907.", a message which is of
> absolutely no use to BigBoss.
> So that's why I feel also, that just passing some low level exception on
> to BigBoss has little actual value.

There are at least three solutions to this.

1) Use exceptions that have an error code that does exactly what yours    does, and use your function(s) to throw anew:
procedure BigBoss(); begin   try     MiddleManager();   except     on e: Exception do       raise f(e);   end; end;
2) Use exceptions that have a data payload that accumulates    information about errors as it unwinds. Rethrow with a new message,    with more general information prepended to detailed information.    Don't display the detailed information by default; have it in    behind a "More..." box or logged someplace.
procedure JuniorEngineer(); begin   try     LowError:= SomelowlevelAPI;   except     on e: Exception do       raise EMyError.Create(e.Message);   end; end;
// ...
procedure BigBoss(); begin   try     MiddleManager();   except     on e: EMyError do       raise EMyError.CreateChained(e.Stuff);     on e: Exception do       raise EMyError.Create(e.Message);   end; end;
> > If you're application needs to print, and you don't care whether it
> > prints or not, then the application shouldn't be designed in such a way
> > as to make the stability of the system state dependant on whether or
> not
> > an exception is raised!
> 
> True, there should be an exception handler to protect this.
> The point was, that if the TForm.Print method had simply returned an
> error code I could've skipped that part and just left it as "I've done
> what I can, and I'm not going to try harder; if it fails, it's not my
> fault anyway and the user has to figure it out.". (e.g. printer not
> installed, blablabla).  It is an error from a printing perspective, but
> due to the spec of my application ("send job to printer", not "guarantee
> it is printed") it is not a fault, so an exception is inappropriate for
> me at that point.

So let the application handle the exception:

try   Print; except   on e: Exception do     Application.HandleException(e); end;
or however it goes. At least it lets the user know that something is wrong and gives them a clue, instead of leaving them wondering if the printer is plugged in.
-- Barry
--   If you're not part of the solution, you're part of the precipitate. Team JEDI: http://www.delphi-jedi.org NNQ - Quoting Style in Newsgroup Postings   http://web.infoave.net/~dcalhoun/nnq/nquote.html
FYI: Phrase searches are enclosed in either single or double quotes
 
 
Originally created by
Tamarack Associates
Wed, 09 Oct 2024 16:47:12 UTC
Copyright © 2009-2024
HREF Tools Corp.