Thread overview | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
August 17, 2001 throws? | ||||
---|---|---|---|---|
| ||||
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 Re: throws? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Russ Lewis | 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 Re: throws? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chris Friesen | 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 Re: throws? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Russ Lewis | 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 Re: throws? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chris Friesen | "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 Re: throws? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Russ Lewis | 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 Re: throws? | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Carney | 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 Re: throws? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christophe de Dinechin | 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 Re: throws? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Russ Lewis | 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 Re: throws? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christophe de Dinechin | 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
|
Copyright © 1999-2021 by the D Language Foundation