Exception Specifications

H

Herb Sutter

Jens Theisen said:
Stuart Golodetz said:
Whether exception specifications are a good thing or not is certainly up for
discussion :) What I don't understand though is what purpose is served by
enforcing them at runtime. If you're going to enforce them, surely it should
be at compile-time? I was just wondering if there's some technical
difficulty making that impossible, or at any rate very hard?

I disagree with the other answers to your question - I find exception
specifications almost useless for that reason; and in practice, indeed
most people don't use them. To quote Herb Sutter: [...]
If someone know why exception specifications are as brain-dead as they
are in C++, I'd be intruiged to hear. My guess is some compatibility
rationale.

Essentially, exception specifications are a wonderful idea in basic
principle, but no one really knows how to design them.

There are two major approaches, and both have serious problems. Java chose
static enforcement (at compile time, as suggested above), and C++ chose
dynamic enforcement. Interestingly, I see Java people ask "why not enforce
these dynamically?" about as often as I see C++ people ask "why not
enforce these statically?"

Briefly:

When you go down the Java path, people love exception specifications until
they find themselves all too often encouraged, or even forced, to add
"throws Exception," which immediately renders the exception specification
entirely meaningless. (Example: Imagine writing a Java generic that
manipulates an arbitrary type T...)

When you go down the C++ path, people love exception specifications until
they discover that violating one means invoking terminate, which is almost
never what you want.

For more, see:

"A Pragmatic Look At Exception Specifications"
C/C++ Users Journal, 20(7), July 2002.
http://www.gotw.ca/publications/mill22.htm

particularly the "Issue the Second" subhead.

Herb
 
J

Jens Theisen

1. you guarantee that no exception is thrown form a (usually low
level) function. This eg. is important to implement assignment
operators.
2. you guarantee that the specified and only the specified
exception(s) is(are) thrown from a function. Since exception
specifications are part of the contract between the user and you, the
implementer, all high level library interfaces should explicitly
specify exceptions in code.

In what way do provide exception specifications more than catch
blocks?

void foo() throw()
{
...
}

is basically equivalent to

void foo()
{
...
}
catch(...)
{
unexpected();
}

So what's good about them?

Jens
 
J

Jens Theisen

Herb Sutter said:
For more, see:

"A Pragmatic Look At Exception Specifications"
C/C++ Users Journal, 20(7), July 2002.
http://www.gotw.ca/publications/mill22.htm

particularly the "Issue the Second" subhead.

Actually, my quote was from that article. :) It's not there
following your link, I took it from `exceptional c++ design'.

I can't tell if I would be happy with the Java approach - I'm not
experienced enough in Java to tell. But don't we agree that, in their
current form in C++, they are a redudant nuisance for compiler vendors
and a waste of time for any curious newbie to the language? I may be
harsh, but what is the benefit if there is any?

Regards,

Jens
 
R

Roland Pibinger

Besides, trivial examples are great for classrooms and CTO meatings but
in general they are of fairly limited applicability.

The following article provides a balanced view of C++ exception
handling and esp. exception specifications. In sum:

"Not every function in a component or layer should be capable of
dealing with exceptions. Usually, try blocks and associated catch
clauses are used by functions that are the entry points into a program
component. The catch clauses are designed to handle exceptions that
the component does not want to let propagate to higher levels of the
program. Exception specifications (...) are also used with the
functions that are the entry points into a component to guard against
the escape of unwanted exceptions to higher levels of the program."

http://www.informit.com/articles/printerfriendly.asp?p=31537&rl=1
 
I

Ian Collins

Jens said:
Actually, my quote was from that article. :) It's not there
following your link, I took it from `exceptional c++ design'.

I can't tell if I would be happy with the Java approach - I'm not
experienced enough in Java to tell. But don't we agree that, in their
current form in C++, they are a redudant nuisance for compiler vendors
and a waste of time for any curious newbie to the language? I may be
harsh, but what is the benefit if there is any?
The only benefit (and a marginal one at that) is as a documentation aid
for drivers at the bottom of a call chain. Once a function calls
another, they become a nuisance.
 
S

Stuart Golodetz

Jens Theisen said:
Actually, my quote was from that article. :) It's not there
following your link, I took it from `exceptional c++ design'.

I can't tell if I would be happy with the Java approach - I'm not
experienced enough in Java to tell. But don't we agree that, in their
current form in C++, they are a redudant nuisance for compiler vendors
and a waste of time for any curious newbie to the language? I may be
harsh, but what is the benefit if there is any?

Regards,

Jens

I wouldn't really describe myself as experienced where Java is concerned,
but I've been coding for the last couple of years in it rather than in C++
(for reasons to do with my course) and I don't find the Java way of doing it
especially onerous. I quite like it, actually, which was partly why I
wondered if there was a reason it couldn't be done like that in C++. (I know
different languages do things differently - that's often a good thing - but
exception specifications in C++ aren't exactly ideal.)

Regards,
Stu
 
S

Stuart Golodetz

Jens Theisen said:
In what way do provide exception specifications more than catch
blocks?

void foo() throw()
{
...
}

is basically equivalent to

void foo()
{
...
}
catch(...)
{
unexpected();
}

So what's good about them?

Jens

As implemented, not much, as far as I can see. I think that's the conclusion
to draw, unfortunately.

Stu
 
S

Stuart Golodetz

Bart said:
So what do you do when your network connection fails? Or when a simple
memory allocation fails? Do you catch every possible exception and then
re-throw the corresponding DBexcept equivalent? What practical value is
added by this approach as opposed to just letting everything that you
don't care about go through?

In Java you have checked and unchecked exceptions. Things like memory errors
would be unchecked exceptions which don't have to be included as part of the
exception specification.
Besides, trivial examples are great for classrooms and CTO meetings but
in general they are of fairly limited applicability. What do you do
when a third party plug-in doesn't respect its contract? Do you just
die because you didn't expect it?

Regards,
Bart.

Get an alternative one, work around the problem, write your own, ... The
point about having compile-time exception specifications (if possible) is
that it never gets to the stage where the program will terminate because of
some unexpected exception. The specifications get checked only when you
compile the code. Unfortunately that's not the way exception specifications
work in C++, apparently for various reasons suggested elsewhere in the
thread.

Regards,
Stu
 
T

tragomaskhalos

Stuart said:
I wouldn't really describe myself as experienced where Java is concerned,
but I've been coding for the last couple of years in it rather than in C++
(for reasons to do with my course) and I don't find the Java way of doing it
especially onerous. I quite like it, actually, which was partly why I
wondered if there was a reason it couldn't be done like that in C++. (I know
different languages do things differently - that's often a good thing - but
exception specifications in C++ aren't exactly ideal.)

As I see it the idiomatic C++ view of what should be deemed an
exception corresponds to what in the Java world is an Error or a
Runtime exception - ie a should-not-happen that no sane person would
want to deal with explicitly, so that in both languages one usually
avoids writing an exception spec for these. Java then extends the
notion to all sorts of other situations that are not really
"exceptional" - eg FileNotFound - for which it makes an exception
specification mandatory. C++ libraries typically choose to deal with
this last category via non-exception means (checking a status field for
example). The Java way is appropriate for a language that doesn't
really trust the programmer not to screw up. The C++ way is appropriate
for a language that credits the programmer with more intelligence than
is sometimes warranted. But the point is that both approaches are
different but appropriate to the languages' intended constituencies.
 
R

Roland Pibinger

As implemented, not much, as far as I can see. I think that's the conclusion
to draw, unfortunately.

You can programmatically control what type of exception is thrown from
your function with simple try/catch/catch(...) blocks within you
function. You are not helplessly at the mercy of low level or third
party functions. How do you come to your strange conclusion?

Best regards,
Roland Pibinger
 
S

Stuart Golodetz

Roland Pibinger said:
You can programmatically control what type of exception is thrown from
your function with simple try/catch/catch(...) blocks within you
function. You are not helplessly at the mercy of low level or third
party functions. How do you come to your strange conclusion?

Best regards,
Roland Pibinger

Well, for one thing: suppose said third-party function has its own exception
specification and fails to abide by it (the person writing it slipped up,
maybe it got changed by someone else who wasn't paying careful enough
attention, etc.). At that point, whenever it throws something not in the
specification, std::unexpected() will get called. As a client of the
third-party function, there's nothing you can do about it. Wrapping it in a
try block etc. won't help. You can't work around the problem.

Regards,
Stu
 
J

Jens Theisen

You can programmatically control what type of exception is thrown from
your function with simple try/catch/catch(...) blocks within you
function. You are not helplessly at the mercy of low level or third
party functions. How do you come to your strange conclusion?

If you could make a proper example of how they do something good that
couldn't be done with catch blocks, posting such would help
understanding. I don't know what you're getting at.

Regards,

Jens
 
R

Roland Pibinger

Well, for one thing: suppose said third-party function has its own exception
specification and fails to abide by it (the person writing it slipped up,
maybe it got changed by someone else who wasn't paying careful enough
attention, etc.).

If the third-party function breaks the contract with you it's their
fault.
At that point, whenever it throws something not in the
specification, std::unexpected() will get called. As a client of the
third-party function, there's nothing you can do about it. Wrapping it in a
try block etc. won't help. You can't work around the problem.

A third party library has a bug. That's pretty normal. Due to
exception specifications it's clear who is to blame.

Best regards,
Roland Pibinger
 
S

Stuart Golodetz

Roland Pibinger said:
If the third-party function breaks the contract with you it's their
fault.


A third party library has a bug. That's pretty normal. Due to
exception specifications it's clear who is to blame.

Best regards,
Roland Pibinger

Allocating blame isn't everything. Well, it might be 99% of everything,
perhaps... :) But seriously, sometimes you just want the damn thing to work.
Telling everyone "We're sorry our program doesn't work - it's *their* fault"
isn't always what you're after.

Stu
 
P

Pete Becker

Stuart said:
Well, for one thing: suppose said third-party function has its own exception
specification and fails to abide by it (the person writing it slipped up,
maybe it got changed by someone else who wasn't paying careful enough
attention, etc.). At that point, whenever it throws something not in the
specification, std::unexpected() will get called. As a client of the
third-party function, there's nothing you can do about it. Wrapping it in a
try block etc. won't help. You can't work around the problem.

You work around it by installing your own unexpected handler, which
throws an exception that satisfies the throw specifier.

--

-- Pete

Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.
 
R

Roland Pibinger

Allocating blame isn't everything. Well, it might be 99% of everything,
perhaps... :) But seriously, sometimes you just want the damn thing to work.
Telling everyone "We're sorry our program doesn't work - it's *their* fault"
isn't always what you're after.

How do you react when they dereference a NULL pointer or when they run
out of bounds? Why should the violation of an exception specification
be treated differently?

Best regards,
Roland Pibinger
 
R

Roland Pibinger

If you could make a proper example of how they do something good that
couldn't be done with catch blocks, posting such would help
understanding. I don't know what you're getting at.

There seems to be the misconception that exception specifications will
inevitably crash your application because you cannot (in a larger
application) track which exceptions are thrown in lower level (third
party) functions (and hence unexpected() will be called).
The brute force approach to control which exceptions are thrown is to
wrap function bodies in try/catch blocks. (Before you ask ... No, I
don't think that each and any function should have exception
specifications; see the link to the article by Lippman and LaJoie in
another post.)

struct MyExcept : std::runtime_error {
MyExcept (const char* s): std::runtime_error (s) {}
};


inline void badThirdPartyFun() {
throw "hehe";
}


inline void myFun() throw (MyExcept) {
try {
// ...
badThirdPartyFun();
// ...
} catch (MyExcept& ex) {
throw;
} catch (std::exception& ex) {
throw MyExcept (ex.what());
} catch (...) {
throw MyExcept ("something really wrong");
}
}


int main() {
try {
myFun();
} catch (MyExcept& ex) {
std::cout << ex.what() << std::endl;
}
}

The more elegant solution is a reusable exception filter similar to
what is described here:
http://article.gmane.org/gmane.comp.lib.boost.devel/132551

Best wishes,
Roland Pibinger
 
J

Jens Theisen

There seems to be the misconception that exception specifications will
inevitably crash your application because you cannot (in a larger
application) track which exceptions are thrown in lower level (third
party) functions (and hence unexpected() will be called).

I appreciate that this doesn't have to be the case. I'm just wondering
what value exception specifications can add to simple catch blocks.
inline void myFun() throw (MyExcept) {
try {
// ...
badThirdPartyFun();
// ...
} catch (MyExcept& ex) {
throw;
} catch (std::exception& ex) {
throw MyExcept (ex.what());
} catch (...) {
throw MyExcept ("something really wrong");
}
}

How does this differ from

inline void myFunc() /* throw MyExcept */ try
{
...
} catch(MyExcept const& ex) {
throw;
} catch(std::exception const& ex) {
throw MyExcept (ex.what());
} catch(...) {
throw MyExcept ("something really wrong");
}

?

What does your code provide that mine doesn't?

In can only think of: The documentation might not be in sync with the
proper code; but in that case, the library is buggy in both code
snippets - it's just a call to unexpected in yours and an exception
propagation in mine; I even prefer the latter if the library is buggy
in that way.

None of your cited articles give an answer to this very legitimate
question.

Regards,

Jens
 
S

Stuart Golodetz

Pete Becker said:
You work around it by installing your own unexpected handler, which throws
an exception that satisfies the throw specifier.

--

-- Pete

Author of "The Standard C++ Library Extensions: a Tutorial and Reference."
For more information about this book, see www.petebecker.com/tr1book.

Fair enough. Thinking about it, though, presumably if there are two or more
such situations, you'd need to keep changing the unexpected handler?

Stu
 
S

Stuart Golodetz

Roland Pibinger said:
How do you react when they dereference a NULL pointer or when they run
out of bounds? Why should the violation of an exception specification
be treated differently?

Best regards,
Roland Pibinger

You're probably right, it shouldn't :) I'm having one of those "I've got
tangled up in my own argument" moments. I'm still not sure I like the way
exception specifications work in C++ though. Ah well.

Regards,
Stu
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top