Exception Specifications

S

Stuart Golodetz

Hi all,

Just wondering whether there's any reason why exception specifications are
enforced at runtime, rather than at compile-time like in Java? (This was
prompted by reading an article on GOTW, incidentally.) Is there something
about C++ that makes it harder/impossible to check at compile-time?

Cheers,
Stu
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

Stuart said:
Just wondering whether there's any reason why exception specifications are
enforced at runtime, rather than at compile-time like in Java?

Beacause is a loose of time. I've seen plenty of Java code samples full of:

try something; catch anything required by the specification: Do nothing;
 
S

Stuart Golodetz

Julián Albo said:
Beacause is a loose of time. I've seen plenty of Java code samples full
of:

try something; catch anything required by the specification: Do nothing;

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?

Cheers,
Stu
 
P

peter koch

Stuart Golodetz skrev:
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 believe it is hard. Consider:

std::vector<int> v;
.....

int i = v.size() > 0? v.at(0):0;
Should that statement be assumed to throw or not?
While it is easy for us to see, it is more difficult for a compiler.
And it can be made even more difficult if v.at(0) is replaced by a
function-call with v as a parameter. I believe you can see the point?

/Peter
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

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?

As shown by my sample, checking it at compile time does not enforce
anything. When people see a message from the compiler, immediately add code
like this. Or instead of doing nothing they abort the program, thus
effectively doing the check at runtime but having to write code to do it.

Surely C++ compilers can add a check and issue a warning when explicit
violations of the specification are detected, the reason they not do it is
that almost anybody wants it.
I was just wondering if there's some technical difficulty making that
impossible, or at any rate very hard?

People habitually don't add features or options to a compiler, or any other
program of certain size and complexity, just because there is not
impossible or very hard to do it. They do it when the authors think, or a
bunch of users tell him, that it will be useful.

If you are talking about the language standard, not the features of concrete
compilers, I suggest you to read "The design and evolution of C++".
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

peter said:
I believe it is hard. Consider:

std::vector<int> v;
....

int i = v.size() > 0? v.at(0):0;
Should that statement be assumed to throw or not?

By the point of view of checking specifications is easy: the statement can
throw if and only if vector::size or vector::at can throw.
And it can be made even more difficult if v.at(0) is replaced by a
function-call with v as a parameter. I believe you can see the point?

In that case, the specification of that function is checked, same difficult.
 
J

Jens Theisen

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:

'In brief, don't bother with exception specifications. Even experts
don't bother.'

And the boost coding guidelines discourage using them either.

There are some minor uses for them that have to do with optimisations
a compiler can do when he knows that exceptions can't occur, but they
are really unusable for what they are for in language like java: To
document what functions throw and enforce this documenation.

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.

Jens
 
B

Bo Persson

Julián Albo said:
By the point of view of checking specifications is easy: the
statement can throw if and only if vector::size or vector::at can
throw.

But vector::size doesn't throw, and vector::at isn't called if the
condition is such that it could throw. So is this statement throwing
or not? Can the compiler detects that?
In that case, the specification of that function is checked, same
difficult.

The other problem is with templates, where the throw spec really
depends on the template parameter

template<class T>
void do_something(T x); // might throw for some Ts

How do we express that?


Bo Persson
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

Bo said:
But vector::size doesn't throw, and vector::at isn't called if the
condition is such that it could throw. So is this statement throwing
or not? Can the compiler detects that?

What compiler? Maybe a compiler that does it can be written, at least for
standard functions with well defined behavior, but I don't think there is a
great demand for such feature. By the way, in this example you can drop
'at' and use operator [ ] instead.
The other problem is with templates, where the throw spec really
depends on the template parameter
template<class T>
void do_something(T x); // might throw for some Ts
How do we express that?

I suppose that a compiler that check the specifications at compile time
'java style' will check at complete specialization of the template time.
Supposing that such compiler will exist any time. One can imagine a
sintaxis to express something as: "can throw what T::somefunc throws", but
I suspect that such complications will never be used by any programmer.
 
J

Jerry Coffin

Hi all,

Just wondering whether there's any reason why exception specifications are
enforced at runtime, rather than at compile-time like in Java? (This was
prompted by reading an article on GOTW, incidentally.) Is there something
about C++ that makes it harder/impossible to check at compile-time?

The following is based primarily on recollection, so it may need to be
taken with a grain of salt.

In a phrase, backward compatibility. Exception specifications were added
to C++ after there were a number of implementations of exception
handling. These were consistent enough that it was considered reasoanble
and important to maintain compatibility with them. To maintain
compatibility with this code, the rule was made that lack of an
exception specification meant "can throw anything."

Unfortunately, that also meant that essentially all existing code was
seen (by the compiler) as being able to throw anything -- even pure C
code that had no notion of exception handling at all.

If exception specifications were enforced at compile time, new code that
used them would have had to do one of two things: either rewrite all
existing code to include exception speciifications (incidentally,
breaking all C compatibility) or else include a 'catch(...)' clause in
the new code to catch and convert the (probably nonexistent) "other"
exceptions to something it was allowed to throw.

Neither of these was seen as acceptable, leaving run-time enforcement as
nearly the only possible solution.
 
S

Stuart Golodetz

Jerry Coffin said:
The following is based primarily on recollection, so it may need to be
taken with a grain of salt.

In a phrase, backward compatibility. Exception specifications were added
to C++ after there were a number of implementations of exception
handling. These were consistent enough that it was considered reasoanble
and important to maintain compatibility with them. To maintain
compatibility with this code, the rule was made that lack of an
exception specification meant "can throw anything."

Unfortunately, that also meant that essentially all existing code was
seen (by the compiler) as being able to throw anything -- even pure C
code that had no notion of exception handling at all.

If exception specifications were enforced at compile time, new code that
used them would have had to do one of two things: either rewrite all
existing code to include exception speciifications (incidentally,
breaking all C compatibility) or else include a 'catch(...)' clause in
the new code to catch and convert the (probably nonexistent) "other"
exceptions to something it was allowed to throw.

Neither of these was seen as acceptable, leaving run-time enforcement as
nearly the only possible solution.

--
Later,
Jerry.

The universe is a figment of its own imagination.

Hmm :) Assuming your recollection is accurate, it does make a fair amount of
sense. It's a tad unfortunate that it went that way, though. Oh well, I
suppose we'll just have to make do without using exception specifications.
Thanks for the explanation, anyhow.

Cheers,
Stu
 
J

Jerry Coffin

[ ... ]
Hmm :) Assuming your recollection is accurate, it does make a fair amount of
sense. It's a tad unfortunate that it went that way, though. Oh well, I
suppose we'll just have to make do without using exception specifications.

I originally thought it was unfortunate, but I've changed my mind. I've
since become convinced that exception specifications (at least as
currently defined) are a fundamentally mistaken design that runs
directly counter to the intent and usefulness of exception handling in
the first place.

One of the basic ideas of exception handling is that the code that
detects a problem rarely has the context to deal appropriately with that
problem -- and in fact, the two will be separated by some arbitrary (but
often large) distance both conceptually and in the call chain. One of
the primary advantages of exception handling is that it allows the
intermediate levels in that call chain to ignore all but those
exceptions can (at least help to) handle. Other than that, their sole
obligation is to be written in an exception-safe fashion.

Exception specifications directly violate that, however. Instead of
allowing all the intermediate levels to ignore all but the exceptions to
which they can contribute handling, exception specifications demand that
all the software, at all the intermediate layers, excplicitly know and
acknowledge _all_ of the exceptions that might orignate from anything
they might call. This is not merely impractical, but negates much (if
not most) of the advantage exception handing provides in the first
place.

I believe virtually nobody really even _wants_ this. What they really
want isn't an assurance that every level in a call chain is aware of all
the exceptions that may originate down the call chain. Rather, the want
an assurance that some code at SOME level in the call chain knows how to
handle all of the exceptions that may happen in whatever it calls. If we
could do THAT at compile time (or more likely link time, since it needs
a view of the program as a whole) it would probably be truly worthwhile.

Exception specifications wouldn't really be very helpful in that though.
To enforce this at compile time, we'd basically start from the lowest
level in a particular call stack, and put together a list of all the
exceptions that can be thrown from that level. We'd then take a step up
the call stack, and add in all the exceptions that level can throw, and
so on. At each level we'd also look for any exception handlers, and
examine their contents to see what exceptions that came from below would
be caught at that level. We'd have to look at the contents of the
handler to see whether it re-throws the current exception. Those that
are caught but not re-thrown could be subtracted from the list of
possible exception. Of course, the compiler would also have to take
inheritance into account -- catching a base class obviously catches all
derived classes.

If there are any exceptions left in the list when we've looked at any
exception handlers in main, these are exceptions that can be thrown but
never caught. Being able to give at least a warning for that situation
would almost certainly be useful. The difficult part of this analysis
would probably be intermediate catch blocks that might only re-throw an
exception conditionally -- and if the condition related to the type of
the exception, it could be difficult to sort out which exceptions that
were caught mnight be re-thrown and which never would.
 
D

Dave Steffen

Stuart Golodetz said:
Jerry Coffin said:
Hi all,

Just wondering whether there's any reason why exception
specifications are enforced at runtime, rather than at
compile-time like in Java?
[...]
Neither of these was seen as acceptable, leaving run-time enforcement as
nearly the only possible solution.
Hmm :) Assuming your recollection is accurate, it does make a fair
amount of sense. It's a tad unfortunate that it went that way,
though. Oh well, I suppose we'll just have to make do without using
exception specifications. Thanks for the explanation, anyhow.

One other issue, though: exception specifications are IIRC nearly
impossible to deal with correctly when writing templates. You don't
know, when writing the template (either function or class) what
operations on the templated type may or may not throw, nor do you
know what do to with them. I don't think anybody's come up with a
good way for templates and exception specs to play nicely together.
 
G

Geo

Stuart said:
Hi all,

Just wondering whether there's any reason why exception specifications are
enforced at runtime, rather than at compile-time like in Java? (This was

C++ is NOT Java, why would you even hope that it might work the same,
especially since Java exception handling is horrible, at least C++'s is
so broken that it is unusable (in fact it is dangerous to use it), and
therefore you never neeed to worry about it.
 
R

Roland Pibinger

C++ is NOT Java, why would you even hope that it might work the same,
especially since Java exception handling is horrible, at least C++'s is
so broken that it is unusable (in fact it is dangerous to use it), and
therefore you never neeed to worry about it.

Neither is Java exception handling 'horrible' (it's just different
from C++) nor are C++ exception specifications 'broken'. WRT to the
latter you propagate the widespread 'Stroustrup-had-a-bad-day' myth.
It declares that everything in the C++ language is fine (more or
less), just exception specifications are 'broken' and 'unusable'. The
same article is usually quoted as reference.
It's true that C++ exception specifications are not standardized in
the most practical way (they are not even standardized as Stroustrup
describes them in his book). But they are not more 'broken' than other
C++ language elements like templates or the look-up rules.
Exception specifications make sense for at least 2 use cases:
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.

Best regards,
Roland Pibinger
 
B

Bart

Roland said:
Neither is Java exception handling 'horrible' (it's just different
from C++) nor are C++ exception specifications 'broken'. WRT to the
latter you propagate the widespread 'Stroustrup-had-a-bad-day' myth.
It declares that everything in the C++ language is fine (more or
less), just exception specifications are 'broken' and 'unusable'. The
same article is usually quoted as reference.
It's true that C++ exception specifications are not standardized in
the most practical way (they are not even standardized as Stroustrup
describes them in his book). But they are not more 'broken' than other
C++ language elements like templates or the look-up rules.
Exception specifications make sense for at least 2 use cases:
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.

You also guarantee that your whole aplication will crumble whenever you
or anything that you call breaks that contract. I really don't see the
point, beside the moderate documentation value of such specifications.
But even then, everyone knows that destructors and assignment operators
are nothrow.

Yes, crashing early is better, yes, I know about all the pretty stuff
like "contracts" that looks very good on whiteboards and in
conferences. But when you get down to pragmatic every-day details a
contract like this may not even be enforceable in a dynamic run-time
environment where many things can happen, and bringing the whole
application down because one of the zillions of components broke its
contract is not acceptable in many real world situations.

Regards,
Bart.
 
R

Roland Pibinger

You also guarantee that your whole aplication will crumble whenever you
or anything that you call breaks that contract...
Yes, crashing early is better, yes, I know about all the pretty stuff
like "contracts" that looks very good on whiteboards and in
conferences. But when you get down to pragmatic every-day details a
contract like this may not even be enforceable in a dynamic run-time
environment where many things can happen, and bringing the whole
application down because one of the zillions of components broke its
contract is not acceptable in many real world situations.

You seem to belief that one cannot programmatically control which
exception(s) may be thrown from a function (and therefore not use
except. spec.). Of course, you can. As a library user I want reliable
information about what a function may throw, eg.

class Database {
public:
void connect (...) throw (DBexcept);
};

or maybe even

class Database {
public:
ErrorCode connect (...) throw();
};


Best wishes,
Roland Pibinger
 
B

Bart

Roland said:
You seem to belief that one cannot programmatically control which
exception(s) may be thrown from a function (and therefore not use
except. spec.). Of course, you can. As a library user I want reliable
information about what a function may throw, eg.

class Database {
public:
void connect (...) throw (DBexcept);
};

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?

Besides, trivial examples are great for classrooms and CTO meatings 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.
 
B

Bart

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?

Besides, trivial examples are great for classrooms and CTO meatings but

Typo there. Should be 'meetings'.

Regards,
Bart.
 
G

Gavin Deane

Bart said:
Besides, trivial examples are great for classrooms and CTO meatings 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?

The first thing you should do is consider an alternative supplier. As
long as the concept of a third party plug-in (or any other API) failing
to respect its contract [*] is considered by users of plug-ins to be in
any way expected or acceptable, software engineering will remain the
woefully immature discipline it currently is.

Gavin Deane
 

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

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,906
Latest member
SkinfixSkintag

Latest Threads

Top