Topic: Exceptions++


Author: whipp@roborough.gpsemi.com (David Whipp)
Date: Wed, 9 Mar 1994 14:15:41 GMT
Raw View


Author: fjh@mundil.cs.mu.OZ.AU (Fergus Henderson)
Date: Wed, 16 Mar 1994 11:59:27 GMT
Raw View
cbarber@bbn.com (Christopher Barber) writes:

>>>>>> "BL" == Bill Leonard <bill@amber.csd.harris.com> writes:
>
>    BL>   Static checking of exceptions is fine by me, providing you can
>    BL> work out technical problems with type checking and templates,
>    BL> and providing that the use of throw signatures remains optional.
>
>There really is no major technical problem here once the exception
>signature is added to function types.

I disagree.  The lack of signature polymorphism means that static
checking would be overly restrictive, especially in the context of
templates and callbacks.

--
Fergus Henderson - fjh@munta.cs.mu.oz.au




Author: bill@amber.csd.harris.com (Bill Leonard)
Date: 7 Mar 1994 22:55:49 GMT
Raw View
In article <1994Mar3.095629.10515@tid.es>, pascual@gonzo.tid.es (Pascual Juan) writes:

> In Short:
> =========
>
>     1.- There is no unexpected exceptions.
>
>     2.- If a function wants to throw (directly or indirectly) an exception
>  that doesn't match with the ones declared in its exception signature
>  (the same or derived) then a compilation error is generated.
>
>     3.- No exception signature means "throw xmsg" instead "throws unexpected"
>  (xmsg is the base class of standard exceptions propossed).

This is the part I object to, because I don't want or need to use throw
signatures at all.  I don't see any advantage to using them.

It still seems to me that this is not an essential part of static checking
of exceptions.  The default "throws anything" is better if you don't want
to use signatures at all.  For those who *do* want to use them, they'll
have to do more work by adding the appropriate signatures or by wrapping
calls to non-signatured functions in try blocks.  Gee, that sounds like the
same work they want *me* to do.  I think those people should shoulder the
burden instead.

As I previously pointed out, changing the throw signatures is, for me, a
heavy burden because I use libraries owned by someone else.  I'd have to
change header files (to put "throw(...)" on all functions) that I don't
own.  A colleague of mine pointed out that changing the header file might
not be enough, or even correct.  What if the compiler needs to generate
different code for a function that says "throw(...)" vs. "throw()"?  The
binary copy of my library wasn't compiled with the signature, so I'm out of
luck.

I'll summarize my position, and then get out of here, because I think the
argument is becoming unproductive.

  Static checking of exceptions is fine by me, providing you can work out
  technical problems with type checking and templates, and providing that
  the use of throw signatures remains optional.

  The default signature should be "throws anything", to make the use of
  signatures truly optional.

  The safety and reliability arguments are, as far as I am concerned, a red
  herring because I don't think non-use of signatures is inherently less
  safe than statically-checked signatures.  (Run-time checking of
  signatures may be another issue, and frankly I see no reason to have it.
  But there may be good arguments in favor of it that I haven't yet heard.)

--
Bill Leonard
Harris Computer Systems Division
2101 W. Cypress Creek Road
Fort Lauderdale, FL  33309
bill@ssd.csd.harris.com

These opinions and statements are my own and do not necessarily reflect the
opinions or positions of Harris Corporation.

------------------------------------------------------------------------------
"I can do trivial things pretty trivially."
                                                  Tom Horsley
------------------------------------------------------------------------------




Author: pascual@gonzo.tid.es (Pascual Juan)
Date: Tue, 8 Mar 1994 11:31:22 GMT
Raw View
In article <2lgbdl$eib@travis.csd.harris.com>, bill@amber.csd.harris.com (Bill Leonard) writes:
|> In article <1994Mar3.095629.10515@tid.es>, pascual@gonzo.tid.es (Pascual Juan) writes:
|>
|> > In Short:
|> > =========
|> > ...
|> >     3.- No exception signature means "throw xmsg" instead "throws unexpected"
|> >  (xmsg is the base class of standard exceptions propossed).
|>
|> This is the part I object to, because I don't want or need to use throw
|> signatures at all.  I don't see any advantage to using them.

Let me explain you the same I did to Brad Daniels: (~ = mail from me to Brad)

~ This point is included to get existing code compatible. A function who does
~ not deal with exceptions are really dealing with them as soon as standard
~ libraries will. if your function does a division (a=b/0) it can throw
~ exceptions your old code didn't expected. But WE don't want UNEXPECTED
~ exceptions. So existing code (existing prototyping) can throw at least
~ standard exceptions. That is the reason I thought about xmsg as the default
~ exception. Every existing function is implicit saying: "I can throw xmsg's".
~ People who don't want to touch his code can be happy.

If you "don't want or need to use throw signatures at all" you do CAN using
my collect of proposals. Compiler does hard work for you. This hard work
includes checking mistakes you can do as soon as you use a library who throws
exceptions. It will tell you "Hey man, your code would explode because
function f() can throw class Z exceptions you don't deal with, so I wont
generate code". You can avoid using libraries who throws their own exceptions
(if market provides it to you), but you and exception-free libraries will
HAVE TO deal with standard library (a=b/0). I want a standard specification
in the language who forces compilers to do hard work for you.

~                                .... We can be happy because no exceptions
~ run away from exception signature, and there won't be any unexpected. New
~ code is forced to be strict with non-system exceptions, and there will be
~ safe code.

I guess it is a good solution for both extremes.

|> It still seems to me that this is not an essential part of static checking
|> of exceptions.  The default "throws anything" is better if you don't want
|> to use signatures at all. ...

No, I insist: If you have code with no exceptions prototyped like this:

  ReturnValue Function(Param);

you WON'T have to touch your code to say compiler "I want to propagate (ignore)
system exceptions thrown in the body of this function" because it assumes it
if you don't say nothing. Compiler sees your code as if you have wroten:

  ReturnValue Function(Param) throw(xmsg);

It is just like default return value:

  some_other_function(Param);
is equal to:
  int some_other_function(Param);

I hope this make my collect a little bit clearer.
--
-------------------------------------------------------------------------------
 ||||  ##     ####                    |         Pascual Juan         |    _V_
 ||||  ## _|_ ## ##   Telefonica I+D  | E-mail: pascual@gonzo.tid.es |  _(,|,)`
 @@@@  ##  |  ## ##  (Telefonica R&D) |    Phone: +34-1-337-47-04    | | ___ ')
 @@@@  ##     ####                    |    fax:   +34-1-337-42-22    | |_|`__/
-------------------------------------------------------------------------------




Author: swf@tdat.ElSegundoCA.NCR.COM (Stan Friesen)
Date: Tue, 8 Mar 94 08:37:29 PST
Raw View
In article <2lgbdl$eib@travis.csd.harris.com>, bill@ssd.csd.harris.com writes:
|> In article <1994Mar3.095629.10515@tid.es>, pascual@gonzo.tid.es (Pascual Juan) writes:
|>
|> > In Short:
|> > =========
|> >     3.- No exception signature means "throw xmsg" instead "throws unexpected"
|> >  (xmsg is the base class of standard exceptions propossed).
|>
|> This is the part I object to, because I don't want or need to use throw
|> signatures at all.  I don't see any advantage to using them.

Neither do I, *but* ...

|> of exceptions.  The default "throws anything" is better if you don't want
|> to use signatures at all.  ...
|>
|> As I previously pointed out, changing the throw signatures is, for me, a
|> heavy burden because I use libraries owned by someone else.  I'd have to
|> change header files ...

With this proposal things really aren't that bad.  All you need to do is
to make sure all of your exceptions are derived from class xmsg.  Given
multiple inheritance, this is easy enough to do.  The result of doing this
is that, for you, the default, "throws(xmsg)", *acts* like "throws(...)"

--
swf@elsegundoca.ncr.com  sarima@netcom.com

The peace of God be with you.




Author: pascual@peggy.tid.es (Pascual Juan)
Date: Tue, 8 Mar 1994 17:45:11 GMT
Raw View
I mailed Brad Daniels to clarify some dark points of my collect. I wrote:

PJ> [...]
PJ> But if you define an exception signature in a function, you are saying
PJ> your function will throw out EXCLUSIVELY the exceptions declared at the
PJ> signature, as told in points 1 & 2. We can be happy because no exceptions
PJ> run away from exception signature, and there won't be any unexpected. New
PJ> code is forced to be strict with non-system exceptions, and there will be
PJ> safe code.
PJ> [...]

and he answered me:

BD> What you've written coincides more-or-less with where I currently stand,
BD> except that I'm not fully decided whether xmsg/unchecked exceptions should
BD> or should not be implicit in all exception signatures.  I've been leaning
BD> toward having such signatures included in all exception signatures, so that
BD> the implementation can generate such exceptions for e.g. floating point
BD> errors. I don't think there's much advantage to be had from requiring anyone
BD> who adds an exception signature to explicitly list unchecked exceptions
BD> as one of the types of exceptions it may generate.

You almost convinced me. I put it there in an excess of purism, but you say
me there is no need of that restriction. I thought about it because I see
exception signature as "the list of exceptions that a function can throw
to his caller" so:

  PJ: If there is no list, compiler will use the default list (who
 is filled just with xmsg)

This behaviour can be seen in the following code:

 void f_3() throw (Y) // Signature means "throw (Y)",
 {                    // not "throw (Y, xmsg)".
   ...
   char * p = new char[81]; // Can throw "xalloc", a derived
   ...                      // class of xmsg
 } // Compiler error!!!

But it can be simpler if we use your proposal (as I understand it):

  BD: Always add xmsg to the list of exceptions that can be thrown.

This behaviour can be seen in the following code:

 void f_3() throw (Y) // Signature means "throw (Y, xmsg)",
 {
   ...
   char * p = new char[81]; // Can throw "xalloc", a derived
   ...                      // class of xmsg
 } // Compiles fine.

It can have some troubles with signatures who throw derivated instances of
xmsg like xalloc. If a function put in his signature "throw (xalloc)" I
don't know what could be the correc behaviour: Do I want to throw xmsg
and xalloc? Can compiler separate them? Can it be sintactically correct?

When you overload a function with a derived parameter, compiler gives an
error to you:

 class Base {...};
 class Derived: Base {...};

 void f(Base);     // Compile-time error!!
 void f(Derived);  // both can accept Derived instances.

It can be necessary to throw derived exceptions as they are, not as the base
class point of view. You can see it in the following code:

 void f_1() throw(xalloc) // I want my callers can see my exceptions as
 {                        // "complete" xalloc, not just its xmsg part.
   ...
   char * p = new char[81]; // Can throw "xalloc", a derived
   ...                      // class of xmsg
 } // Compiles fine.

If you forces everybody to throw xmsg, they won't ever catch their derivated.

Please send comments. I like this feedback because it makes us to see it in
different ways.

Let's make a safe C++.
-
-------------------------------------------------------------------------------
 ||||  ##     ####                    |         Pascual Juan         |    _V_
 ||||  ## _|_ ## ##   Telefonica I+D  | E-mail: pascual@gonzo.tid.es |  _(,|,)`
 @@@@  ##  |  ## ##  (Telefonica R&D) |    Phone: +34-1-337-47-04    | | ___ ')
 @@@@  ##     ####                    |    fax:   +34-1-337-42-22    | |_|`__/
-------------------------------------------------------------------------------




Author: clint@vsfl.demon.co.uk (Ian Cameron Smith)
Date: Tue, 8 Mar 1994 18:01:16 +0000
Raw View
In article <1994Mar3.095629.10515@tid.es> pascual@gonzo.tid.es writes:

> I want to collect all the proposals made about compile-time checking of
> exception signatures made by:
>
>         Brad Daniels (daniels@biles.com)
>         Christopher Barber (cbarber@bbn.com)
>         Jerry Schwarz (?)
>         Tucker Taft (stt@spock.camb.inmet.com)
>         Sam Fenster (fenster@age.cs.columbia.edu)
>
> and me, who joins them with some addings.
>
>         Pascual Juan (pascual@gonzo.tid.es)   <- Not an ANSI member.

[ Proposed exception scheme... ]

> I just wanted to be constructive.

My $0.00002 says *very* constructive; well done and thanks.
--
Ian Cameron Smith                            |
Principal Software Engineer                  |    "Don't quote me"
Virtual Software Factory LTD                 |         -- me
clint@vsfl.demon.co.uk  +44 (0)425 474484    |




Author: cbarber@bbn.com (Christopher Barber)
Date: 08 Mar 1994 22:17:43 GMT
Raw View
>>>>> "BL" == Bill Leonard <bill@amber.csd.harris.com> writes:

    BL>   Static checking of exceptions is fine by me, providing you can
    BL> work out technical problems with type checking and templates,
    BL> and providing that the use of throw signatures remains optional.

There really is no major technical problem here once the exception
signature is added to function types.

    BL> The default signature should be "throws anything", to make the
    BL> use of signatures truly optional.

I would rather see the default be "throw nothing", considering that most
code out there that does not have an exception specification probably
does not throw any exceptions except perhaps xalloc.

    BL>   The safety and reliability arguments are, as far as I am
    BL> concerned, a red herring because I don't think non-use of
    BL> signatures is inherently less safe than statically-checked
    BL> signatures.

This, of course, assumes a default of "throws anything".   I don't
think that the reliability argument is a red herring.  Consider the
following:

In a statically checked world:

    class Xfoo { /* ... */ } ;

    void foo() throw(Xfoo)
    {
        // ...
        throw Xfoo(/* important recovery info here */);
    }

    int main()
    {
        try {
            foo() ;
        }
        catch (Xfoo &xfoo) {
            xfoo.recover() ;
            // continue on....
        }
    }

In a world with missing signatures:

    class Xfoo { /* ... */ };

    void foo()
    {
        throw Xfoo(/* ... */) ; // suprise!!!
    }

    int main()
    {
        try {
            foo() ;
        }
        catch (...) {
            // Whoops, we didn't know we were supposed to catch
            // an Xfoo!  Probably just have to clean up and die...
        }
    }

The problem here is that if the author of foo() decides to throw non-fatal
exceptions and leave them out of the signature, the user of foo() has to
rely on whatever documentation is available to know that fact.  Even worse
it would be possible for Xfoo to be declared local to foo so that users of
foo() would not even be able to catch an Xfoo if they wanted to!  In a
statically checked world, Xfoo would have to be declared publicly in
order to be included in the signature of foo(), so this problem could not
occur.  In other words, the reliability of a library with respect to
exceptions would depend upon documentation that is not part of the code
itself.

You might be willing to take these risks, but the fact that there are risks
at all indicates there are some real concerns here.

- Chris
--
Christopher Barber
(cbarber@bbn.com)




Author: pascual@gonzo.tid.es (Pascual Juan)
Date: Thu, 3 Mar 1994 09:53:42 GMT
Raw View
I built an orthogonal collection of proposals made in comp.std.c++ to make C++
exceptions safer. I think it could satisfy both extremes: Bill Leonard and
Brad Daniels, and I want to stop this useless fight.

As Bill Leonard said:
> Let me emphasize again that it is only this default that I object to.  If
> you were only willing to take the burden yourself of putting exception
> signatures on all your functions, we could agree.

You won't need to touch any line of code to get the behaviour you want, and
Brad Daniels (and me) can sleep without the fear of an explosion or in my
case a digital short-cut in the phone comunications in 20 millions of users
(AT&T has to remember a recent bug two years ago, who let west coast isolated).

Let's make C++ a very good language. Post serious enhancements to my
collection and then com.std.c++ can offer a formal proposal to the committee.

I changed the subject of the thread in order to avoid a .kill file entry
and get the most feedback it can. Original collection will be re-posted
as a followup to this post. Read it carefully before killing it.

By the way, Matt Austern (matt@physics2.berkeley.edu) said:
> Andrew Koenig, one of the authors of the original exception proposal,
> has said that he didn't want exception specifications to be part of
> the language at all.  I think we ought to take his opinion seriously:
> he has a good deal more experience with exceptions than most of us.

Last paragraph is like tell us "Hey kids, don't play silly buggers and let
adults do their job!".

Andrew Koenig is a wise man, but human, and humans can be wrong.
I do hope he read my collection and join us.

--
-------------------------------------------------------------------------------
 ||||  ##     ####                    |         Pascual Juan         |    _V_
 ||||  ## _|_ ## ##   Telefonica I+D  | E-mail: pascual@gonzo.tid.es |  _(,|,)`
 @@@@  ##  |  ## ##  (Telefonica R&D) |    Phone: +34-1-337-47-04    | | ___ ')
 @@@@  ##     ####                    |    fax:   +34-1-337-42-22    | |_|`__/
-------------------------------------------------------------------------------




Author: pascual@gonzo.tid.es (Pascual Juan)
Date: Thu, 3 Mar 1994 09:56:29 GMT
Raw View
In article <1994Mar3.095342.10330@tid.es>, pascual@gonzo.tid.es (Pascual Juan) writes:
|> I changed the subject of the thread in order to avoid a .kill file entry
|> and get the most feedback it can. Original collection will be re-posted
|> as a followup to this post. Read it carefully before killing it.
Here it goes:

I want to collect all the proposals made about compile-time checking of
exception signatures made by:

 Brad Daniels (daniels@biles.com)
 Christopher Barber (cbarber@bbn.com)
 Jerry Schwarz (?)
 Tucker Taft (stt@spock.camb.inmet.com)
 Sam Fenster (fenster@age.cs.columbia.edu)

and me, who joins them with some addings.

 Pascual Juan (pascual@gonzo.tid.es)   <- Not an ANSI member.

In Short:
=========

    1.- There is no unexpected exceptions.

    2.- If a function wants to throw (directly or indirectly) an exception
 that doesn't match with the ones declared in its exception signature
 (the same or derived) then a compilation error is generated.

    3.- No exception signature means "throw xmsg" instead "throws unexpected"
 (xmsg is the base class of standard exceptions propossed).

    4.- Pointers to function in general (member, non-member, static) will
 add new features in order to declare it with the exceptions thrown.

    5.- There is no function overloading with different exception signature,
 just like different return value in oveloaded funtion declarations.

    6.- Type-Safe-Linkage adds the exceptions throwed by a function in the
 name of the symbols generated. There will be linking incompatibilities
 between symbols with and without exceptions, because functions
 that can't throw exceptions are not part of the language.

Explanation:
============

    1.- No unexpected
    -----------------
 Unexpected weakens C++ language. It could make ANSI C++ a good
 aproximation to Smalltalk and its "method not found". As we
 can see, this is incompatible with safe software.

    2.- Compile-time checking
    -------------------------
 A function can throw an exception directly using the reserved word
 "throw", and indirectly if it calls other functions that throws
 exceptions directly or indirectly. Compile-time checking is
 obvious with direct exceptions, and indirect exceptions can be
 checked if their respective signatures has been checked.

 Direct and indirect exceptions has to be declared at scope of the
 function we are dealing, in order to know their inheritance. The
 following code:

  class xBase { ... }; // Declaration of
                       // exception base.

  class xDerived : public xBase { ... }; // Declaration of a
                                         // derived exception.

  void f(int i) throw xBase
  {
    ...
    throw xDerived(data);
    ...
  }

 can't be checked if compiler haven't both class declarations, same as
 return value of functions:

  class Base { ... }; // Declaration of
                      // return value base.

  class Derived : public Base { ... }; // Declaration of a
                                       // derived return value.

  Base & f(int i)
  {
    ...
    return some_derived; // decladed as:
  }                      //   Derived some_derived(data);

 It is easy to build an indirect exception example like previous one.

    3.- No signature means "throw xmsg"
    -----------------------------------
 This could make existing code compatible just by recompiling, because
 when you get a failure in the default "new" operator or a division
 by zero, REALLY EXCEPTIONALS exceptions will be thrown. This ones
 can be even catched by safe functions or its caller, and warned with
 a compiler option.

 Look out! Declaring a function with an exception signature breaks
 this rule, and strict compile-time checking works on:

  void f_1() // No signature means "throw xmsg"
  {
    ...
    char * p = new char[81]; // Can throw "xalloc", a derived
    ...                      // class of xmsg
                } // Compiles fine.

  void f_2() // No signature means "throw xmsg"
  {
    ...
    function_with_signature(); // Can throw "Z", that is not a
    ...                        // derived class of xmsg.
                  ...                        // No "catch (Z & z)" is done
                } // Compiler error!!!

  void f_3() throw Y // Signature means "throw Y",
  {                  // not "throw Y, xmsg".
    ...
    char * p = new char[81]; // Can throw "xalloc", a derived
    ...                      // class of xmsg
                } // Compiler error!!!

 In this way, new code will be safer, and old code can still work.

 I doubt if no signature has to mean "throw xmsg" or "throw xruntime".
 Acording to standard library proposals, there will be a standard
 exception hierarchy:

   class xmsg { ... };
   class xruntime : public xmsg { ... };
   class xalloc : public xruntime { ... };

 As I am not a committee member, and I have no more information than
 their names, I don't know if xmsg will be enought to handle its
 derived through virtual functions. However, xruntime has a beautifull
 name to be the default exception.

    4.- New features in pointers to function
    ----------------------------------------
 Pointers to function will have to be declared with exception
 signature:

  void (*fp)() throw Z = function_with_signature; // See before.

 And pointers declared without signature will mean "throw xmsg":

  void (*fp)() = f_1; // See before.

 In this way, new code will be safer, and old code can still work.

    5.- No signature overloading
    ----------------------------
 Compilers will have a behaviour similar to overloading return values:

  int    f();
  char * f();

  main() { f(); } // Compiler Error: Which f()?

 You can't distinguish them, same as exceptions:

  void f() throw Y;
  void f() throw Z;

  main() { f(); } // Compiler Error: Which f()?

 This is applicable to virtual functions and templates.

    6.- Type-Safe-Linkage
    ---------------------
 Caller functions won't link with a function who throws exceptions
 who doesn't match with the ones declared in the signature.
 Thus, next functions generates new symbols:

  void f(int) throw Z;         // Becomes f__Fi_1Z
  void * operator new(size_t); // Becomes __nw6size_t_4xmsg

 This will make a "brand new" symbol for operator new, and existing
 libraries won't link with this "brand new" new. Providers can
 supply the ANSI C++ libC.a and the old libOldC.a without exceptions
 during a transition lap. When you link with a non-ANSI lib you
 know what you risk at, and you will get exactly the old behaviour.

 Functions who doesn't throw exceptions (C libraries) has to be
 declared out of the language with the directive: extern "C".
 If you have a "pre-ANSI C++" library, you have to use a new
 directive: extern "C++". Its functions will have Type_Safe_Linkage
 but they won't assume 'no signature means "throw xmsg"' but
 'no signature means "throw nothing"'. It makes a bridge to
 existing libraries with only 3 lines of code added:

  extern "C++"                  // One
  {                             // Two
  #include "my_pre_ansi_lib.h"
  }                             // Three

END of Proposal
===============

I just wanted to be constructive.

--
-------------------------------------------------------------------------------
 ||||  ##     ####                    |         Pascual Juan         |    _V_
 ||||  ## _|_ ## ##   Telefonica I+D  | E-mail: pascual@gonzo.tid.es |  _(,|,)`
 @@@@  ##  |  ## ##  (Telefonica R&D) |    Phone: +34-1-337-47-04    | | ___ ')
 @@@@  ##     ####                    |    fax:   +34-1-337-42-22    | |_|`__/
-------------------------------------------------------------------------------