[net.lang.c] event-handling approach to errors

henry@utzoo.UUCP (Henry Spencer) (03/03/85)

> >I am deeply suspicious of event-handling primitives; I don't think I
> >have ever seen a good way of doing them.  Lots of bad ways, though.
> 
> There are very good systems that use a stack-discipline exception mechanism.
> Upon an error, the most recently set error handler is given a chance to
> interpret the error, and either provide a correction action at the point
> of error, provide a failure alternative at a point of call (a la setjmp), or
> pass the error (or a modified form of the error) to the next most recent
> handler.  A system-established default handler at the bottom of the stack
> will print a message and exit if no user-defined action is taken.

What happens if an exception occurs within an exception handler?  How do
you provide a correction action for something like a subscript violation?
How do you inspect enough global context to find out what's *really* wrong?
(Note that optimizing compilers complicate the beejeezus out of figuring
out precisely where something went wrong and what to do about it.)  Most
particularly, how do you make it clear in the source that all this odd
behind-the-scenes machinery may be invoked at random times?

Obviously my original comment didn't sink in:  I know of no *good* way
of doing exception handling.  Everything you describe is obviously
desirable in an exception-handling mechanism, but the details tend to
be very complex and decidedly ugly.  I have seen exception-handling
mechanisms whose description was half of the total description of the
language.  I have seen a substantial Ph.D. thesis, from a major CS
department, solely devoted to the design of an exception-handling
mechanism.  There is a marked lack of simple, general, powerful ideas
in this area.  Barring very specialized applications, the cost-benefit
ratio of anything more complex than (say) Unix signals seems poor.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

ndiamond@watdaisy.UUCP (Norman Diamond) (03/04/85)

> > There are very good systems that use a stack-discipline exception mechanism.
> > Upon an error, the most recently set error handler is given a chance to
> > interpret the error, and either provide a correction action at the point
> > of error, provide a failure alternative at a point of call (a la setjmp), or
> > pass the error (or a modified form of the error) to the next most recent
> > handler.  A system-established default handler at the bottom of the stack
> > will print a message and exit if no user-defined action is taken.

> What happens if an exception occurs within an exception handler?

Each exception handler is established at a particular level in the stack.  If
an exception handler blows up, then its level in the stack has the exception,
and earlier-level handlers may be invoked....

> How do
> you provide a correction action for something like a subscript violation?

Usually such a case is not correctable.  If the code has a bug, it doesn't
matter if good exception handlers or bad exception handlers are available;
the answer is to print a message (maybe dump, maybe ask the user if he wants
a dump), and die.

Of course, there are occasionally uses.  Someone in a numerical application
could decide that everything out of range is 0.  Someone doing quicksort could
decide that the left end always compares lower, and the right end always
compares higher -- though they'd have to return to the appropriate part of
the code.  This may improve efficiency if the hardware provides checking of
array bounds.  It is ugly of course.  (The assembly language I wrote quicksort
in is also ugly.)

> How do you inspect enough global context to find out what's *really* wrong?

Ah!  The real problem!  That, I don't know the answer to.  Maybe an AI
program can read a dump.

> Most
> particularly, how do you make it clear in the source that all this odd
> behind-the-scenes machinery may be invoked at random times?

How do you make it clear in the source code that execution time errors
might cause the program to abort?  Or that in critical applications
(including operating systems), behing-the-scenes machinery has to be
invoked to attempt a recovery, anyway?

> Obviously my original comment didn't sink in:  I know of no *good* way
> of doing exception handling.

Perfect exception handlers will be delivered with perfect programming
languages and perfect operating systems.  Meanwhile, why ignore useful tools
when they're available?  Really Henry, you usually aren't that shortsighted.

-- 

   Norman Diamond

UUCP:  {decvax|utzoo|ihnp4|allegra}!watmath!watdaisy!ndiamond
CSNET: ndiamond%watdaisy@waterloo.csnet
ARPA:  ndiamond%watdaisy%waterloo.csnet@csnet-relay.arpa

"Opinions are those of the keyboard, and do not reflect on me or higher-ups."

jc@mit-athena.UUCP (John Chambers) (03/05/85)

>                                                            ...  How do
> you provide a correction action for something like a subscript violation?

Hey, MasterCard knows how to handle this.  On several occasions, I've
overflowed (overflown?) my credit limit, and they responded promptly
by upping the limit!  It takes care of the problem quite nicely.

Seriously, in a language that allows dynamic allocation of space (as do
C, APL, and many other languages), it is not unreasonable to consider
such a solution.  I've had several applications where it was a real 
pain to initially allocate things to their largest possible size.  If
an array will usually only hold 2 or 3 items, but may grow to 50000 in
some cases, you don't want to allocate 50000 in all cases.  If you have
several such arrays, what do you do?  It would be really nice if you
could intercept the out-of-bounds reference, determine that it was for
one of the select list of "growable" arrays, and re-allocate the one
involved to have more space.  

			John Chambers

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (03/06/85)

Anyone really interested in this topic should look at the way
VAX/VMS supports exception handlers.  It is pretty good.

henry@utzoo.UUCP (Henry Spencer) (03/07/85)

> > Most
> > particularly, how do you make it clear in the source that all this odd
> > behind-the-scenes machinery may be invoked at random times?
> 
> How do you make it clear in the source code that execution time errors
> might cause the program to abort?  Or that in critical applications
> (including operating systems), behing-the-scenes machinery has to be
> invoked to attempt a recovery, anyway?

I have thought for a long time that absence of most execution-time errors
is a statically-checkable property, given some cooperation from the
language and the programmer.  That aside...  One thing that helps is if
the association of exception handlers with code in which they handle
exceptions is static rather than dynamic.  I.e., which blocks enclose
which others, rather than who gets called before who.  Unfortunately,
this aggravates things like the exceptions-inside-handlers issue, and
makes them significantly less useful.

> > Obviously my original comment didn't sink in:  I know of no *good* way
> > of doing exception handling.
> 
> Perfect exception handlers will be delivered with perfect programming
> languages and perfect operating systems.  Meanwhile, why ignore useful tools
> when they're available?  Really Henry, you usually aren't that shortsighted.

Note that I didn't ask for a perfect exception handler, just a good one.
I haven't seen any.  Mechanisms resembling Unix signals are too simple
to do all you want.  Anything fancier seems to invariably end up in
the trap of more and more features, with the result of extreme complexity
and singularly poor cost:benefit ratio.  And it *still* doesn't do all
you want.

Personally, I think that the only realistic way to do exception handling
is to have another process handle the exception, if only because there
is no other way to guarantee an intact environment when an exception hits.
But I have no idea how to arrange the details.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

jim@ISM780B.UUCP (03/07/85)

>Obviously my original comment didn't sink in:  I know of no *good* way
>of doing exception handling.

Henry, your comment did sink in, but it is merely a statement about your
personal perception, and it is extremely arrogant of you to expect everyone
to just throw their hands in the air and give up because *you* don't trust
exception mechanisms.  I do trust them, and they solve *real* problems
that UNIX signals or error message/exit from low level routines don't even
begin to touch.  We can discuss the relative merits of these systems,
but please accept that there are people on this net at least as clever
as you.  Your ad hominem assumptions that anyone who doesn't agree with you
hasn't had it sink in or hasn't considered the issues or doesn't understand
the real world will only limit your own ability to learn.

-- Jim Balter, INTERACTIVE Systems (ima!jim)

mwm@ucbtopaz.CC.Berkeley.ARPA (03/08/85)

>                                                            ...  How do
> you provide a correction action for something like a subscript violation?

Complain if the user doesn't catch it. The user then gets to use it for walking
dynamic arrays, to wit:

	i := 0
	while true do
		<mangle array element array[i]>
		end except when bounds: end

After seeing that a few times, it reads as naturally as:

	for (i = 0; i < bounds; i++)
		<mange array element array[i]> ;

	<mike

		

wenn@cmu-cs-g.ARPA (John Wenn) (03/09/85)

>Personally, I think that the only realistic way to do exception handling
>is to have another process handle the exception, if only because there
>is no other way to guarantee an intact environment when an exception hits.
>But I have no idea how to arrange the details.
>				Henry Spencer @ U of Toronto Zoology

If you want to see a reasonably good and complete signal mechanism, look into
Mesa (a Xerox homegrown language, from the same company that brought you
SmallTalk).  You can do all the normal things you would expect:  normal
signals, attaching handlers to blocks or statements, passing parameters
through the signal, aborting the operation, retrying the operation from the
beginning, continuing the operation, and continuing with new parameters (e.g.
growing an array or string);  and a few things you would not think of
immediately:  deciding that you can't handle the exception after all (which
causes it to look for another exception handler up the call chain), signals
inside of exception handlers, and notification that your operation is being
aborted (which is useful to clean up data inside of monitors, for instance).

It does indeed work by calling run-time machinary that starts a new process
which looks through the call stack for possible exception handlers, and
handles any results (aborting, continuing, etc.).  If there is no handler for
the exception, the debugger is called with the complete environment of the
exception intact. Mesa is run on Xerox homegrown workstations (Dolphin,
Dandelion, Dorado, aka 1100, 1108, 1132 aka 8010) with its own operation
system.  The details of the signal mechanism is messy, but not much more than
you would expect for something this complex.

/john wenn

mark@rtech.ARPA (Mark Wittenberg) (03/09/85)

> It would be really nice if you
> could intercept the out-of-bounds reference, determine that it was for
> one of the select list of "growable" arrays, and re-allocate the one
> involved to have more space.  
> 
> 			John Chambers

Of course this is essentially what the early "ed" editor did (does);
for all I know its derivatives do too:  when its array of line pointers
ran out of space it did a "free(); realloc()" to "grow" (copying only if needed)
the array.  I don't know how portable this use of realloc is though.
To be clear, ed doesn't "intercept the out-of-bounds reference"; it detects
when it's run out of space without generating an error.  I know it's not quite
the same thing, but this is the only common UN*X program that I know of which
does this "free & realloc" trick; anybody else know of others?
-- 

Mark Wittenberg
Relational Technology
zehntel!rtech!mark
ucbvax!mtxinu!rtech!mark

henry@utzoo.UUCP (Henry Spencer) (03/16/85)

> If you want to see a reasonably good and complete signal mechanism, look into
> Mesa (a Xerox homegrown language, from the same company that brought you
> SmallTalk).  [It's got lots of good stuff.]

I have read both general descriptions of Mesa and the Mesa manual itself.
I also read an interesting retrospective on the language, which among
other things said (roughly), "the exception mechanism is too complex
and gives far too much freedom; it is terribly easy to hang yourself
(or the next guy who maintains your code) with it, and this happens
too often for comfort".  I confess it didn't sound that bad to me, but
they're the ones with Mesa experience.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

wenn@cmu-cs-g.ARPA (John Wenn) (03/17/85)

>I have read both general descriptions of Mesa and the Mesa manual itself.
>I also read an interesting retrospective on the language, which among
>other things said (roughly), "the exception mechanism is too complex
>and gives far too much freedom; it is terribly easy to hang yourself
>(or the next guy who maintains your code) with it, and this happens
>too often for comfort".  I confess it didn't sound that bad to me, but
>they're the ones with Mesa experience.

You're right, it isn't quite that bad.  The entire signal mechanism is very
powerful and general, too much so for most applications.  As with any
powerful feature you can hang yourself if you misuse it, or don't fully
understand it.  On the otherhand, it's nice to have the power when you need
it.  I never used anywhere near the full generality of Mesa signals, but I
did use things that aren't available anywhere else (CLU, Ada, C, etc.).  The
entire subject of how you handle exceptional conditions is not understood.
Mesa provides one extreme.  The right answer probably is a bit more moderate.

/John