[comp.lang.c++] Exception Handling in C++

dianne@mead.UUCP (Dianne Glickfield) (04/11/90)

Hello,
     I was wondering if anyone could give me some information on the exception
handling design that Bjarne Stroustrup and Andrew Koening presentend and the 
" C++ at Work " conference in November 1989.  I would be interested in hearing
what was said.  Email or posting is fine.  Thanks in advance.

_______

Dianne Steele Glickfield			Product Delivery Systems
Mead Data Central				dianne@uccba.uc.edu
P.O. Box 933					...!uccba!mead!koala!dianne
Dayton, OH  45401				(513) 865-1293

zweig@cassius.cs.uiuc.edu (Johnny Zweig) (04/13/90)

dianne@mead.UUCP (Dianne Glickfield) writes:
>Hello,
>     I was wondering if anyone could give me some information on the exception
>handling design that Bjarne Stroustrup and Andrew Koening presentend and the 
>" C++ at Work " conference in November 1989.  I would be interested in hearing
>what was said.  Email or posting is fine.  Thanks in advance.
>_______
>Dianne Steele Glickfield			Product Delivery Systems

Bjarne gave a talk about the revised/ANSIfied version of this at the
USENIX C++ Conference in San Francisco the day before yesterday. Michael
Tiemann told us that G++ 1.36 has a similar mechanism (and he seemed to
say that he would probably change it to match Bjarne's specification in the
new paper, though he was unclear on the point).

The basic idea is to introduce blocks with exception-handlers like:

try {
   //some code which might say "throw Foo();" or "throw Bar();"
}
catch(Foo f) {
   //f is an object of type Foo which is the exception -- it's
   //constructor could take arguments so the exception can tell you stuff
}
catch(Bar b){
   //ditto
}

There is also a way that a function can declare what exceptions it might
raise to allow type-safe exception handling (whether functions that lack
a throw-clause are saying they can generate any exception or no exception
is unclear to me; it makes a big difference in what you can do and there
is a nice religious safety vs. flexibility argument associated with
which it is -- I'll read the paper and post which it is if noone else
comments).

So wait until your local library gets a copy of the proceedings and all
will be revealed.

-Johnny Exceptional

zweig@brutus.cs.uiuc.edu (Johnny Zweig) (04/14/90)

zweig@cassius.cs.uiuc.edu (Johnny Zweig) writes:
>....
>There is also a way that a function can declare what exceptions it might
>raise to allow type-safe exception handling (whether functions that lack
>a throw-clause are saying they can generate any exception or no exception
>is unclear to me; it makes a big difference in what you can do and there
>is a nice religious safety vs. flexibility argument associated with
>which it is -- I'll read the paper and post which it is if noone else
>comments).

Because we want C++ programs to be able to call C functions and to keep
the programmer from having to scribble all over everything to have an
exception be passable through all the levels of indirection (i.e. have main()
catch some scary exception that is raised by some low-level math routine) the
decision was made that undecorated functions can throw any exception.

Please note that the syntax given in the paper was changed to that shown
above (the paper says catch(f) raises f, rather than throw()...).  An errata
sheet was handed out at the conference but I doubt the proceedings will be
corrected before copies go out to your local library.

Also, the paper goes into some gibberish (no offense intended to Mr.
Stroustrup, but this section was smoking something) about whether an exception
is an object or a class.  An exception is an object and a handler takes a 
(possibly anonymous) exception as an argument.  The fact that I can say
"catch(Foo){" to catch any object of type Foo (or a subtype of Foo) and be
unable to refer to it is syntactically odd but not tricky to think about.
The paper talks about being able to raise a pointer to an object as if it
were something scary -- I think it looks like function-calling and I always
think of functions as taking objects (though pointers aren't objects in
C++...sigh!).  I would welcome anyone who can explain this to me. It seems
to be because you can't get the right flavor of virtual function when you
pass an object (as opposed to a pointer to an object) -- so you can pass
an object or a pointer to a new object (by saying "throw(new Foo);") but
it is totally ganjafied to say it is both an object and a class.

-Johnny Exceptional

horstman@sjsumcs.sjsu.edu (Cay Horstmann) (04/14/90)

In article <1990Apr13.034540.10997@brutus.cs.uiuc.edu> zweig@cs.uiuc.edu writes:
>
>Bjarne gave a talk about the revised/ANSIfied version of this at the
>USENIX C++ Conference in San Francisco the day before yesterday. 
>The basic idea is to introduce blocks with exception-handlers like:
>
>try {
>   //some code which might say "throw Foo();" or "throw Bar();"
>}
>catch(Foo f) {
>   //f is an object of type Foo which is the exception -- it's
>   //constructor could take arguments so the exception can tell you stuff
>}
...
>So wait until your local library gets a copy of the proceedings and all
>will be revealed.
>
Actually, the paper uses the SAME keyword for throwing and catching:
catch( f() ) throws--see the difference between it and catch( Foo f )?
I am all for keyword saving, but this one is too much. (Well, we should
be grateful he didn't use "virtual" or "static"--the all-purpose keywords
of the 90s.) In his talk he did use "throw" and "catch". 

What is wrong with "raise" and "handle" ? Not catchy enough?

Cay

P.S. The keyword "try" is not really necessary. One could take the
position (like some languages do) that each block can have its own
"handle" clause handling any errors encountered in that block. 

drc@cs.brown.edu (David R. Chase) (04/15/90)

In article <1990Apr13.192428.17008@brutus.cs.uiuc.edu> zweig@cs.uiuc.edu writes:
>>(whether functions that lack
>>a throw-clause are saying they can generate any exception or no exception
>>is unclear to me; it makes a big difference in what you can do and there
>>is a nice religious safety vs. flexibility argument associated with
>>which it is -- I'll read the paper and post which it is if noone else
>>comments).
>
>Because we want C++ programs to be able to call C functions and to keep
>the programmer from having to scribble all over everything to have an
>exception be passable through all the levels of indirection (i.e. have main()
>catch some scary exception that is raised by some low-level math routine) the
>decision was made that undecorated functions can throw any exception.

That's too bad.  Unfortunately, other languages do it the same wrong
way, so it's not clear how much flexibility you sacrifice with default
= "generates no exceptions".  Mick Jordan and Steve Glassman studied
this at length for Modula-2+ and Modula-3, and decided that "raises
none" ought to be the default.  They studied a large collection of
Modula-2+ programs (a compiler, and operating system -- that sort of
large collection) and discovered that (1) they found several latent
bugs by changing the default and (2) they only had to change a few
procedure declarations to make the code compile again.

Now, as far as compatibility with C goes -- that's a bit of a problem.
There's no difficulty at all in the implementation, but you'd have to
introduce some sort of annotation in the declarations for all the
non-C++ procedures.  It shouldn't be necessary to change all the C
code, if exceptions can propagate through several callers.
(Stroustrop got that right, didn't he?  Life is much simpler if the
exceptions just propagate on out until they find a catcher.)

Now, as to the usefulness of "catching things in main()" -- you'll
have to come up with a better example than that.  Speaking from
experience (*) schemes that try to combine both exception-handling and
return codes get a little baroque -- IF people have
exception-handling, then they are apt to use it to signal things like
end-of-file, no-file-found, etc., and pretty soon your C++ (**) code
is completely useless if called from C (***) because the caller will
not see the exception.  In practice, it's either C on the outside
calling something else, or something-else on the outside calling C.
It's possible to write "wrapper procedures" that turn exceptions into
return codes, or return codes into exceptions, but there's really no
reason to expect that programmers will be any more enthusiastic about
this inter-language busy-work than they are about any other
inter-language busy-work (****).

* experience = porting the Acorn "C And Modula Execution Library"
** or Modula-2+, or Modula-3, as the case may be
*** or Fortran, or Pascal
**** For example -- "what if someone wanted to use a garbage
collector?  What does that do to my pointer arithmetic?"

Exception subtyping is a good thing, especially if you plan to build
extensible packages.  Without subtyping, the author of the extensible
package cannot anticipate the exceptions that might be raised by
refinements (subclasses, e.g.) of her code.  In that situation, only
"RAISES any" will provide the necessary flexibility.  With exception
subtyping, the programmer can name the specific interesting exceptions
that might be raised, as well as the general classes that are expected
in the future, without declaring that ANY exception might be raised.
This also allows programmers to write code that is more robust in the
face of future changes -- a client might choose to catch (say)
"divide-by-zero", "end-of-file" and "<the rest of the math errors>"
and "<the rest of the IO errors>".  Future weird math errors (whatever
they might be) will be treated as math errors in the future, even
though we don't know what they are now, and future weird IO errors
will be treated as IO errors in the future.  Other, truly
unanticipated errors will be treated like the disasters that they are.

In summary, a default of "RAISES anything" gives the compiler fewer
opportunities to catch bugs, but it does provide more flexibility, but
the flexibility is almost useless.  Sub and super-typing of exceptions
provides the only flexibility that is really missing if "RAISES any"
is not used.

David Chase