Thread overview
throws?
Aug 17, 2001
Russ Lewis
Aug 17, 2001
Chris Friesen
Aug 17, 2001
Russ Lewis
Aug 17, 2001
Russ Lewis
Aug 18, 2001
John Carney
Aug 24, 2001
Dan Hursh
Aug 18, 2001
Russ Lewis
Aug 19, 2001
kaffiene
August 17, 2001
Is there a reason not to implement a throws declaration?

IMHO, this is good because it enforces design decisions and interfaces. It forces the implementer of the function to either handle the exceptions he can generate, or publish to all his callers what he might do.

August 17, 2001
Russ Lewis wrote:
> 
> Is there a reason not to implement a throws declaration?
> 
> IMHO, this is good because it enforces design decisions and interfaces. It forces the implementer of the function to either handle the exceptions he can generate, or publish to all his callers what he might do.

If I write a function that calls another function (etc, etc...), do I have to include all of their throw list in my throws declaration?  If yes, then it becomes messy.  If not, then what is the point of it since I can't tell just by looking at a function what it can potentially throw?

Chris


-- 
Chris Friesen                    | MailStop: 043/33/F10
Nortel Networks                  | work: (613) 765-0557
3500 Carling Avenue              | fax:  (613) 765-2986
Nepean, ON K2H 8E9 Canada        | email: cfriesen@nortelnetworks.com
August 17, 2001
Chris Friesen wrote:

> Russ Lewis wrote:
> >
> > Is there a reason not to implement a throws declaration?
> >
> > IMHO, this is good because it enforces design decisions and interfaces. It forces the implementer of the function to either handle the exceptions he can generate, or publish to all his callers what he might do.
>
> If I write a function that calls another function (etc, etc...), do I have to include all of their throw list in my throws declaration?  If yes, then it becomes messy.  If not, then what is the point of it since I can't tell just by looking at a function what it can potentially throw?

Yes.  Basically, the theory is that you should either handle the exception (catch it) or alert those who call you that you might throw it.  Yes, it gets messy (declaration wise).  But I think that without it, things get messy implementation wise, which, IMHO, is far worse.

August 17, 2001
Russ Lewis wrote:

> Chris Friesen wrote:
>
> > Russ Lewis wrote:
> > >
> > > Is there a reason not to implement a throws declaration?
> > >
> > > IMHO, this is good because it enforces design decisions and interfaces. It forces the implementer of the function to either handle the exceptions he can generate, or publish to all his callers what he might do.
> >
> > If I write a function that calls another function (etc, etc...), do I have to include all of their throw list in my throws declaration?  If yes, then it becomes messy.  If not, then what is the point of it since I can't tell just by looking at a function what it can potentially throw?
>
> Yes.  Basically, the theory is that you should either handle the exception (catch it) or alert those who call you that you might throw it.  Yes, it gets messy (declaration wise).  But I think that without it, things get messy implementation wise, which, IMHO, is far worse.

Another thought....

New exceptions tend to filter up through the call tree.  That is, if you choose, late in the game, to throw a totally new type of exception, that exception has serious impacts on the other code.  If they consider you a minor function and want to catch all of your errors, then when you add a new exception your are breaking their program.  Thus, a small change in your library might suddenly cause total program crashes for what they consider to be minor errors.

By forcing declaration, you are specifying the impact that the change will have on all of your users.  Anyone who builds a new version of code using yours will get syntax errors because of your declaration change.  They must then think about the best way to change it - they either allow the exception to continue to be thrown further up the tree, or they catch it.  Either way, they are *forced* to at least consider your error conditions, which I consider a Very Good Thing.

August 18, 2001
"Chris Friesen" <cfriesen@nortelnetworks.com> wrote in message news:3B7D59CE.448CFD79@nortelnetworks.com...
> Russ Lewis wrote:
> >
> > Is there a reason not to implement a throws declaration?
> >
> > IMHO, this is good because it enforces design decisions and interfaces. It forces the implementer of the function to either handle the exceptions he can generate, or publish to all his callers what he might do.
>
> If I write a function that calls another function (etc, etc...), do I have
to
> include all of their throw list in my throws declaration?  If yes, then it becomes messy.  If not, then what is the point of it since I can't tell
just by
> looking at a function what it can potentially throw?
>
> Chris

I totally agree with the original poster on this one. Yes, it does mean that functions must declare the exceptions thrown by functions they call. I disagree that this becomes 'messy'. 'Messy' is when lazy programmers let uncaught exceptions propagate up the call stack resulting in upper-level functions having to deal gracefully with exceptions that would have been better handled closer to the source.

When I use a library function I want to know about *all* of the exceptions that it will throw. Rigid exception specification guarantees this.

Cheers,
John Carney.



August 18, 2001
Throw declarations in C++ have a subtle problem: the throw declaration declares the _opposite_ of what the implementation can easily guarantee.

For instance:

    int foo() throw (A) {
        try {
            bar()
        } catch(B&) {
            glop()
        }
    }

what the implementation guarantees is, roughly, that you won't throw B, but there is no throw spec that will let you "say" that.


Christophe

Russ Lewis wrote:

> Is there a reason not to implement a throws declaration?
>
> IMHO, this is good because it enforces design decisions and interfaces. It forces the implementer of the function to either handle the exceptions he can generate, or publish to all his callers what he might do.

August 18, 2001
John Carney wrote:

>
> I totally agree with the original poster on this one. Yes, it does mean that functions must declare the exceptions thrown by functions they call. I disagree that this becomes 'messy'. 'Messy' is when lazy programmers let uncaught exceptions propagate up the call stack resulting in upper-level functions having to deal gracefully with exceptions that would have been better handled closer to the source.
>
> When I use a library function I want to know about *all* of the exceptions that it will throw. Rigid exception specification guarantees this.

There are two philosophies of error recovery: error recovery as cleanup, and error recovery as repair. Eiffel implements the first one, C++ inconsistently implements the second one.

Error recovery as cleanup means that a catch handler does not try to "keep" the exception, but simply to locally cleanup in case of error (close files, release locks, etc). In Eiffel (and LX), by default, exceptions keep propagating, as opposed to C++ where they by default are finished by a catch block. In this philosophy, a component never decides what to do with an error, but leaves it to the component user to decide.

Error recovery as repair assumes that the closer to the source you catch an error, the easier it is to fix, and thus tries to prevent an error from propagating. In my opinion, it generally lends to less robust software, because errors tend to be ignored in running software.

C++ is inconsistent (as I wrote in another post) in that it implements repair-style in the catch block (an exception doesn't propagate unless you explicitly rethrow), but it offers cleanup-style interfaces (the throw spec says what you throw, not what you catch). Interestingly, there is no way to really bring a throw spec and a catch totally in sync. A catch says "I won't throw that", but there is no (simple) way to say "I will throw all but that" (the complex way being "catch that and rethrow, catch dot-dot-dot and ignore", which is ugly.

In short, my recommendation would be to go for an "error recovery as cleanup" model, in which case throw specs are inherently bad (you don't know what kind of errors may occur, you let the caller decide). In the case of "real" code with callbacks, virtual functions, etc, it tends to map to real-life situations better, in my experience.


Christophe

August 18, 2001
Christophe de Dinechin wrote:

> Throw declarations in C++ have a subtle problem: the throw declaration declares the _opposite_ of what the implementation can easily guarantee.
>
> For instance:
>
>     int foo() throw (A) {
>         try {
>             bar()
>         } catch(B&) {
>             glop()
>         }
>     }
>
> what the implementation guarantees is, roughly, that you won't throw B, but there is no throw spec that will let you "say" that.

Actually, I would argue the reverse.  In C++, where you don't have throws
declarations, that is what it means.  But if you *must* declare all possible
thrown exceptions for *every* function, then you know (by its declaration)
what bar() might throw.  You are not saying that foo() throws all exceptions
except B...you are saying that foo() throws any exceptions that bar() might
throw...except that it catches B.

August 19, 2001
I think that a throws declaration is a fantastic idea.  The thing is that it forces programmers to explicitly handle or explicitly delegate the responsibility of dealing with any given exception that can occur in it. This is a really good thing.

C++ ends up with the lame try..catch block in the middle of main to catch everything - which means that any usefull handling (and possibly error recovery) is not done.  The throws declaration tends to make people consider exceptions closer to the source - where they can do something usefull about it.

This is *A VERY GOOD THING* :-)

Peter.


"Russ Lewis" <russ@deming-os.org> wrote in message news:3B7D3698.1A47A8A8@deming-os.org...
> Is there a reason not to implement a throws declaration?
>
> IMHO, this is good because it enforces design decisions and interfaces. It forces the implementer of the function to either handle the exceptions he can generate, or publish to all his callers what he might do.
>


August 24, 2001
	What happens if you have to write bullet proof code.  (Think a
pacemaker.)  I need to know ever error a function could throw at me so I
can make sure to deal with it gracefully.  In you're suggestion you are
pretty much saying "I could throw anything at you, include exception
classes that are out of you're scope."  Writing and maintain throws()
clauses is truly a royal pain, but it does allow for a good amount
certainty that you are handling every known error condition a function
can throw at you, provided that the compiler will actually enforce the
clauses.  (Does C++ require the compiler to gripe?)  Granted it makes
template code much more difficult to write if you are forced to specify
a throws clause.
	Now what we need to design is a sure way to tell the programmer all of
the unknown errors that are in the program. ;-)

Dan

Christophe de Dinechin wrote:
> 
> John Carney wrote:
> 
> >
> > I totally agree with the original poster on this one. Yes, it does mean that functions must declare the exceptions thrown by functions they call. I disagree that this becomes 'messy'. 'Messy' is when lazy programmers let uncaught exceptions propagate up the call stack resulting in upper-level functions having to deal gracefully with exceptions that would have been better handled closer to the source.
> >
> > When I use a library function I want to know about *all* of the exceptions that it will throw. Rigid exception specification guarantees this.
> 
> There are two philosophies of error recovery: error recovery as cleanup, and error recovery as repair. Eiffel implements the first one, C++ inconsistently implements the second one.
> 
> Error recovery as cleanup means that a catch handler does not try to "keep" the exception, but simply to locally cleanup in case of error (close files, release locks, etc). In Eiffel (and LX), by default, exceptions keep propagating, as opposed to C++ where they by default are finished by a catch block. In this philosophy, a component never decides what to do with an error, but leaves it to the component user to decide.
> 
> Error recovery as repair assumes that the closer to the source you catch an error, the easier it is to fix, and thus tries to prevent an error from propagating. In my opinion, it generally lends to less robust software, because errors tend to be ignored in running software.
> 
> C++ is inconsistent (as I wrote in another post) in that it implements repair-style in the catch block (an exception doesn't propagate unless you explicitly rethrow), but it offers cleanup-style interfaces (the throw spec says what you throw, not what you catch). Interestingly, there is no way to really bring a throw spec and a catch totally in sync. A catch says "I won't throw that", but there is no (simple) way to say "I will throw all but that" (the complex way being "catch that and rethrow, catch dot-dot-dot and ignore", which is ugly.
> 
> In short, my recommendation would be to go for an "error recovery as cleanup" model, in which case throw specs are inherently bad (you don't know what kind of errors may occur, you let the caller decide). In the case of "real" code with callbacks, virtual functions, etc, it tends to map to real-life situations better, in my experience.
> 
> Christophe