Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Exception specifications unfortunate, and what about their future?

44 views
Skip to first unread message

DeMarcus

unread,
Nov 20, 2008, 4:37:50 PM11/20/08
to
Hi,

Recently I bought the book C++ Coding Standards by Sutter and
Alexandrescu. The book is good but there's one thing that they comment
in a way that doesn't feel right. I talk about item 75 in the book.

Item 75 says: "Avoid exception specifications.".

The authors have a lot of good arguments for not using exception
specifications, but there's one thing they're missing; the
specifications have a purpose, or at least should have. The authors
neglect this fact with following argument: "People often suggest
switching from dynamically checked exception specifications to
statically checked ones, as provided in Java and other languages. In
short, that just trades one set of problems for another; users of
languages with statically checked exception specifications seem to
equally often suggest switching to dynamically checked ones."

I don't blame the authors, don't take me wrong, but to me it seems like
the exception specifications need to be fixed when two of the most
renowned C++ programmers recommend us to avoid them.

I think statically checked exception specifications (the same way as in
Java) should be implemented because of three things.

1. Prefer *compile time* check before run-time.
2. It helps the programmer to see what exceptions *at least* must be
handled when using a method.
3. *Use* exception specifications rather than avoid them.

Still a method should be able to throw whatever it likes as for instance
std::bad_alloc, and that should not lead to automatic termination. This
way is just like Java can throw new InternalError() without having the
compiler complain if not in the exception specification.


So, what's the future of exception specifications? As I always try to
prepare for the future I have made two base classes.

class ErrorException
class ProblemException

Classes inheriting from ErrorException could be for instance
OutOfMemoryException or InvalidArgumentException.
Classes inheriting from ProblemException could be for instance
FileNotFoundException or PermissionDeniedException.

Quite often do I use exceptions to report problems that can go wrong,
and should be able to go wrong, e.g. FileNotFoundException. From a
programmer's perspective it's good if the compiler complains if I have
missed to catch any of these problems, whereas show stoppers like
OutOfMemoryException is something one would like to handle in a
different way.

My suggestion is to change to statically checked exception
specifications where the compiler complains about all non-caught
exceptions except those derived from some std::error_exception.


Sincerely,
Daniel


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Lance Diduck

unread,
Nov 20, 2008, 6:00:25 PM11/20/08
to
Exceptions in Java and C++ are very different ideas. They just happen
to have the same syntax. Here are some major highlights:

1. C++ exceptions cannot be statically checked, since C++ has no
metadata mechanism like Java. For instance, it is possible to compile
something, and then link in a library that throws types that the
calling program knows nothing about. This happens quite often. Java
has class metadata associated with each package, so it can know at
compile time, even if the source is unavailable.
2. Java exceptions are used as diagnostic tools primarily, to be used
in conjunction with the stack trace. The recoverability is a secondary
role. C++ exceptions are used primarily as system recoverability
mechanism, to be use in conjunction with the destructor. Their
diagnostic features are very limited. A good C++ program will operate
correctly without ever knowing the type of exception thrown. In Java
this is much more difficult.
The perspective can be viewed this way: Java exceptions are concerned
with detecting violations in function preconditions, while C++
exceptions are concerned with protecting class invariants. (this is
why the isValid() functions in C++ libraries are considered bad
form).


So if it is considered bad form to rely on the type of exception
thrown (instead, for diagnostics inherit all exceptions from
std::exception, and print out the message, if that helps) then why
does C++ have exception specifications at all? Good question. I hope
we get rid of them. I used to use them, until I devolved into just
making every function specify throw(std::exception) – that worked,
until I wanted to use something like Xerces --which, since it does not
use ANYTHING in std:: does not play by these rules. Now what? Put in a
bunch of “exception transformers” everywhere? Ha!
Indeed system was far less complicated when I didn’t care what
exceptions were thrown.

So, instead of making C++ exceptions looks like Java (and a LOT of
Java programmers would rather have the C++ semantics) use C++
exceptions the way they were intended – to protect the class invariant
by using transactions. Don’t use them for function preconditions if
you can help it.
See http://www.lancediduck.com/papers/Cpp/UsingOOwithCPP2.htm#_Toc89666392

Lance

Daniel Krügler

unread,
Nov 20, 2008, 6:18:45 PM11/20/08
to
On 20 Nov., 22:37, DeMarcus <demar...@hotmail.com> wrote:
[..]

I cannot much agree. Let me first add that I have some
experience with Java and I have not seen much advantage
for checked exceptions - in contrast, they give you a false
security that nothing else might fail. I have found *lots*
of programmer error's due to this, e.g. consider

interface IMyStream {
void doSomeIoStuff(SomeResource r) throws IOException;
}

void userFunc(IMyStream strm) {
SomeResource res = new SomeResource(...); // Allocate non-memory
resource,
// like file handles or some such
try {
strm.doSomeIoStuff(res);
} catch (IOException e) {
res.dispose();
}
}

This function ('method' in Java nomenclature) can easily cause
resource leaks, just consider a null strm argument (which
throws unchecked NullPointerException) or any other unchecked
exception thrown from doSomeIoStuff (for whatever reason).
[Yes, *you* would certainly use an additional finally block,
but as I said, this is not something, everyone is aware of]

The only exception for my refusal to love checked exception would
be the strict no-throw guarantee - this is a quite important one
and a compiler taking advantage of such beast can easily optimize
the code.

Just my 2 Euro cents,

Daniel Krügler

zai...@zaimoni.com

unread,
Nov 20, 2008, 8:34:34 PM11/20/08
to
On Nov 20, 5:00 pm, Lance Diduck <lancedid...@nyc.rr.com> wrote:
> On Nov 20, 4:37 pm, DeMarcus <demar...@hotmail.com> wrote:
>
> > Hi,
>
> > Recently I bought the book C++ Coding Standards by Sutter and
> > Alexandrescu. The book is good but there's one thing that they comment
> > in a way that doesn't feel right. I talk about item 75 in the book.
>
> > Item 75 says: "Avoid exception specifications.".
>
> > The authors have a lot of good arguments for not using exception
> > specifications, but there's one thing they're missing; the
> > specifications have a purpose, or at least should have. ....

Exception specifications are useful if performance is a non-issue.
That doesn't describe what I work on, so I currently use them only as
a late stage in optimizing for size.

> Exceptions in Java and C++ are very different ideas. They just happen
> to have the same syntax. Here are some major highlights:
>
> 1. C++ exceptions cannot be statically checked, since C++ has no
> metadata mechanism like Java. For instance, it is possible to compile
> something, and then link in a library that throws types that the
> calling program knows nothing about. This happens quite often. Java
> has class metadata associated with each package, so it can know at
> compile time, even if the source is unavailable.

This is a defect of the formats used to represent object files for
linking, not C++ itself. There's nothing preventing a new format for
object code from providing such metadata.
It's just so much faster (man-years? man-decades?) to abuse object
formats optimized for C to represent C++ object files.

marlow...@googlemail.com

unread,
Nov 21, 2008, 8:20:29 AM11/21/08
to
On 20 Nov, 21:37, DeMarcus <demar...@hotmail.com> wrote:
> Recently I bought the book C++ Coding Standards by Sutter and
> Alexandrescu. The book is good but there's one thing that they comment
> in a way that doesn't feel right. I talk about item 75 in the book.
>
> Item 75 says: "Avoid exception specifications.".
>
> The authors have a lot of good arguments for not using exception
> specifications, but there's one thing they're missing; the
> specifications have a purpose, or at least should have.

Yes, but the purpose failed. See an article by Bruce Ekcel at
http://www.mindview.net/Etc/Discussions/CheckedExceptions on java and
checked exceptions. He basically says that C++ tried to offer compile-
time checked exceptions but for technical reasons wound up with
runtime checked but java did not have those problems and does offer
compile-time checked. But unless the software is a 'toy' program,
compile-time exception checks hurt rather than help. They are only
useful on small trivial programs. On larger projects they tend to get
swallowed. So even if C++ could overcome the technical difficulties
(e.g how do you make it work with templates?) then you would have
something that is not very useful.

Opinion is still divided about Ekcel's article but I know where I
stand. I wanted stricter compile-time exception checks in C++ for ages
and even proposed a mechanism for doing it. See
http://www.andrewpetermarlow.co.uk/goodies/proposal.pdf for details.
But as I moved in to java and saw the effects mentioned by Ekcel I
decided to prefer runtime checks in java and to not bother at all in C+
+.

Regards,

Andrew Marlow

Pavel Minaev

unread,
Nov 21, 2008, 2:46:39 PM11/21/08
to
On Nov 21, 2:00 am, Lance Diduck <lancedid...@nyc.rr.com> wrote:

> Exceptions in Java and C++ are very different ideas. They just happen
> to have the same syntax. Here are some major highlights:

> 1. C++ exceptions cannot be statically checked, since C++ has no
> metadata mechanism like Java. For instance, it is possible to compile
> something, and then link in a library that throws types that the
> calling program knows nothing about. This happens quite often. Java
> has class metadata associated with each package, so it can know at
> compile time, even if the source is unavailable.

I disagree. C++ exception specification can be statically checked in
exactly the same way as function types are checked - since they are
(or should be) available on declarations of functions in the header,
the compiler has them available at all times. There is no requirement
for "reflection" or other similar runtime type metadata provider to
implement checked exceptions.

> 2. Java exceptions are used as diagnostic tools primarily, to be used
> in conjunction with the stack trace. The recoverability is a secondary
> role. C++ exceptions are used primarily as system recoverability
> mechanism, to be use in conjunction with the destructor. Their
> diagnostic features are very limited. A good C++ program will operate
> correctly without ever knowing the type of exception thrown. In Java
> this is much more difficult.
> The perspective can be viewed this way: Java exceptions are concerned
> with detecting violations in function preconditions, while C++
> exceptions are concerned with protecting class invariants. (this is
> why the isValid() functions in C++ libraries are considered bad
> form).

I will disagree here as well. For one thing, C++ exceptions can and
are used to signal violations of preconditions - in fact, quite a few
standard library exceptions are specifically dedicated to this
(std::invalid_argument, std::out_of_range, std::domain_error,
std::range_error etc). For another, good Java code will also use
exceptions to protect class invariants in the same way as C++ code
does (and default public constructor paired with some form of
initialize() and isValid() is similarly frowned upon).

Also, I do not see how destructors enter into this picture. Java
finally-blocks play a similar role WRT exceptions and RAII, they just
take more effort to implement and maintain.

This really boils down to the fact that C++ and Java exceptions are,
indeed, the same thing: a non-recoverable dynamic nonlocal transfer of
control mechanism.

> So if it is considered bad form to rely on the type of exception
> thrown

It is? You mean, it is frowned upon catching ios_base::failure from
fstream constructors?

Patrik Kahari

unread,
Nov 21, 2008, 2:51:46 PM11/21/08
to

> The only exception for my refusal to love checked exception would
> be the strict no-throw guarantee - this is a quite important one
> and a compiler taking advantage of such beast can easily optimize
> the code.

I think sutter mentions it in the same book. But the no throw
specification cant really be used by the compiler to optimize code. It
infact carries a performance penalty, because for every function with
a nothrow specifier the compiler has to enforce at runtime that no
exception leaks out of the function. It basically has to enclose the
whole function with a catch(...) and terminate (threw std::unexpected
()) if it catches anything. Not very useful.

Eugene Gershnik

unread,
Nov 21, 2008, 6:57:38 PM11/21/08
to
On Nov 21, 5:20 am, marlow.and...@googlemail.com wrote:
>
> Yes, but the purpose failed. See an article by Bruce Ekcel at
> http://www.mindview.net/Etc/Discussions/CheckedExceptions on java and
> checked exceptions. He basically says that C++ tried to offer compile-
> time checked exceptions but for technical reasons wound up with
> runtime checked but java did not have those problems and does offer
> compile-time checked. But unless the software is a 'toy' program,
> compile-time exception checks hurt rather than help. They are only
> useful on small trivial programs. On larger projects they tend to get
> swallowed.

Replace 'exception' with 'const' and 'swallowed' with 'cast away', and
his (very popular) argument becomes one about the virtue of const
correctness that is endlessly reappearing here.
The difference is that C++ community has experience with statically
checked const and most gurus disagree with identical arguments about
it. To further confuse matters Java's implementation is
(characteristically) poor. They don't have a clear distinction between
exceptions (in C++ sense) and asserts and so some asserts end up
requiring static checks while some exceptions don't.

Just like 'const' (or public/private access control) statically
checked exception are primarily a tool to reason about design and
detect violations of design assumptions early. Both work rather well
in this capacity. People are only disappointed when they try to force
them to do other things and fail. For example some people want 'const'
to enforce physical immutability (see many posts by Walter Bright on
this topic). Others expect exception specifications to physically
guarantee that no other kind of error can ever happen in the function
(see post by Daniel Krugler above).

Apart from the above the main complaint about statically checked
exceptions seems to be that they propagate forcing one to revisit the
entire calling chain when modifying low-level code. This is considered
a nuisance (just like with const) and bad programmers commonly resort
to swallowing everything (or casting const away). This problem is real
but the reason for it is not the exception specifications but
programmers misunderstanding of what they are for. People who
encounter this problem invariably use the following way of designing
their function interfaces:

- write the implementation
- see what exceptions propagating out of the function compiler
complains about
- declare them in function interface
- repeat the process for any implementation change

The problem with this approach is that it is completely backwards.
Static exception specification is a part of a function interface. It
has to be designed upfront (just like argument types and constness
are). If the implementation 'wants' to emit an exception that is not
supported by the interface you either have a design problem or should
convert the low-level implementation exception into the higher-level
exception declared in your interface. When using such approach the
long chains of exception specification propagation disappear. Any
change in low-level implementation that causes a new exception to be
thrown is quickly handled and translated into some higher-level
exception a few caller levels above it. And once in a while you do
discover serious design problems when you find that you cannot
reasonably translate.

> But as I moved in to java and saw the effects mentioned by Ekcel I
> decided to prefer runtime checks in java and to not bother at all in C+
> +.

I would recommend you give it another try. Write exception
specifications upfront based on function semantics without much regard
to implementation details and see if those effects disappear.

--
Eugene

Lance Diduck

unread,
Nov 21, 2008, 7:00:23 PM11/21/08
to
On Nov 21, 2:46 pm, Pavel Minaev <int...@gmail.com> wrote:
> I disagree. C++ exception specification can be statically checked in
> exactly the same way as function types are checked - since they are
> (or should be) available on declarations of functions in the header,
> the compiler has them available at all times. There is no requirement
> for "reflection" or other similar runtime type metadata provider to
> implement checked exceptions.

The compiler certainly does not have every header in a system
available at all times, nor should it. Most well factored libraries
will use so-called private headers, and these signatures are not
available (by design) to the client code.
Lets see what happens:
In a cpp. file, we include headers for three libraries that do the
same thing. This generates a binary for a dynamic link library. So not
only the compiler does not know, but the linker as well does not know
at build time. We only find out at runtime:
#include <liba.h>
#include <libb.h>
#include <libc.h>
void mywrapper(T arg){
if(use_liba)
liba::process(arg)//may throw a liba:exception
else if(use_libb)
libb::process(arg)//may throw a libb:Exception
else
libc::process(arg)//may throw a libc:error
//of course, we are also using std::, which can throw std::exception
}
(for a real world example of this sort of thing, look at the QuickFix
library, which uses exception specification + multiple XML parsers. )

The header has no knowledge of the three libraries:
void mywrapper(T arg);

The exception specification in the header declaration either:
1. Has to list every exception thrown by each library, which breaks
encapsulation, which is the entire point of mywrapper
2. Implement mywrapper to catch every possible exception, and convert
it to a type to match the exception spec. This is extremely tedious
and error prone – if you don’t get it right, BOOM your app terminates
by default. No one want to use mywrapper then.
3. let mywrapper emit any exception, and let the catch point deal with
it.

None of the above is particularly appealing, however, after much trial
and error number three is the most workable. Encapsulation is not
broken if catch(…) is used, there are no tedious exception conversion
routines, and the exception is handled at place designed to deal with
exceptions.

Of course, the client is probably catching using catch(…) which
trashes some hopefully useful diagnostic info. But the system is still
correct, reliable, and encapsulated. If that diagnostic info is
needed, well, then something has to give, but exception specs don’t
help with this.
I really thought they did at one point, and used them religiously,
until they themselves became the major source of system unreliability.

In any case, and A Marlow points out, what if mywrapper were a
template? Such that
template <class A>void mywrapper(T arg){
A::process(arg);
}
There is no possible way for the template author to provide mywrapper
with an exception specification. For static checking to work, the
compiler would have to keep up with the exception spec used for process
(), and somehow the template “inherits” this spec. Not too hard for my
one line example, but consider

template <class A, class B, class C, class D >void mywrapper(T arg){
D::foo(C::bar(arg?B::tricky():A::process(arg)));
}
I suppose that mywrapper could automatically spec the union of the
unholy mess of exception specs, however, there is no programmer who is
ever going to write catch blocks for each case and get it right, even
if they could get info on what the generated exception spec is.

To drive this home, one thing that C++ has that Java does not, is
operator overloading. They can throw as well. Sigh. Or something like
streams, where you can turn exceptions on and off, and indeed, through
some trickery, throw them at a later time. How would a static spec
handle that?

> > 2. Java exceptions are used as diagnostic tools primarily, to be used
> > in conjunction with the stack trace. The recoverability is a secondary
> > role. C++ exceptions are used primarily as system recoverability
> > mechanism, to be use in conjunction with the destructor. Their
> > diagnostic features are very limited. A good C++ program will operate
> > correctly without ever knowing the type of exception thrown. In Java
> > this is much more difficult.
> > The perspective can be viewed this way: Java exceptions are concerned
> > with detecting violations in function preconditions, while C++
> > exceptions are concerned with protecting class invariants. (this is
> > why the isValid() functions in C++ libraries are considered bad
> > form).
>
> I will disagree here as well. For one thing, C++ exceptions can and
> are used to signal violations of preconditions - in fact, quite a few
> standard library exceptions are specifically dedicated to this
> (std::invalid_argument, std::out_of_range, std::domain_error,
> std::range_error etc). For another, good Java code will also use
> exceptions to protect class invariants in the same way as C++ code
> does (and default public constructor paired with some form of
> initialize() and isValid() is similarly frowned upon).

They can be used that way, sure. I have seen programmers use them to
make “typed goto” statements
try{
if(something)throw 1:
throw 1.0;
catch(int){
}catch(float){}
And yes the standard library uses them to signal precondition
violations. The point was that debugging a program that uses C++
exceptions to protect preconditions is very difficult. (The MSVC
debugger does an excellent job in this regard though). The Java
exceptions seemed esp designed to provide stack traces, making them
far easier to use in spotting precondition violations.

Also realize that much of the standard library was designed when there
were very few compilers that actually supported exceptions. The same
story applies for things like member templates, partial specialization
and the like. Around this same time (mid 1990’s) there was much
concern that it was impossible to actually design exception-safe
templates. This of course was proven wrong, but the standard libs were
finalized not long after that.
There was a natural tendency to replace the standard C library return
codes with exception types (which is why we have exceptions of those
types) and use them for preconditions just like they were used in the
C library. However, exceptions are not generalization of return code,
but rather generalizations of longjmp. When people start thinking that
C++ exceptions == return codes, then they are bound to be
disappointed. Java takes the “exception is a generalized return code”
point of view however, and adds in support, as you say, for long
distance jumps.

> Also, I do not see how destructors enter into this picture. Java
> finally-blocks play a similar role WRT exceptions and RAII, they just
> take more effort to implement and maintain.

What finally block does is force the programmer to be conscious of
exactly the path taken from the try to the possible throw point, so
that if something needs a finally (like freeing a lock) then this case
is handled. There are even code samples in the Herlihy book that screw
this up.
This makes it particularly difficult to refactor code. Note, however,
that the plethora of tools available to a Java programmer for this
purpose far outweigh the difficulties imposed by finally blocks.

> This really boils down to the fact that C++ and Java exceptions are,
> indeed, the same thing: a non-recoverable dynamic nonlocal transfer of
> control mechanism.
>
> > So if it is considered bad form to rely on the type of exception
> > thrown
>
> It is? You mean, it is frowned upon catching ios_base::failure from
> fstream constructors?

If you are relying on it for program correctness, then yes. If you are
using the type for diagnostic purposes then no, so for example

try{
ifstream f;
f.exceptions ( ifstream::eofbit | ifstream::failbit |
ifstream::badbit );
f.open(“something”);
//use f;
}catch(ios_base::failure const&e){
std::cerr<<”Oops!! Failed in fstream around “<<__LINE__;
//throw;//should be commented in for correct operation
//OR also use a catch(…) block to handle all other exception
types
}
//more code either called for all cases i..e catch(…) is used, or for
//only nothrow cases, i.e.. throw; is used

In this case I personally prefer
ifstream f;
f.open(“something”);
if(!f)throw std::runtime_error(“could not open \”something\””):
//typically in a macro that also gives me __FILE__ and __LINE__ info

Now I am not trying to fool around with various catch blocks. I
perhaps have two or three such blocks for an entire application. God
forbid if these were finally statements.


Lance

Daniel Krügler

unread,
Nov 21, 2008, 8:05:33 PM11/21/08
to
On 21 Nov., 20:51, Patrik Kahari <patrik.kah...@googlemail.com> wrote:
> > The only exception for my refusal to love checked exception would
> > be the strict no-throw guarantee - this is a quite important one
> > and a compiler taking advantage of such beast can easily optimize
> > the code.
>
> I think sutter mentions it in the same book. But the no throw
> specification cant really be used by the compiler to optimize code. It
> infact carries a performance penalty, because for every function with
> a nothrow specifier the compiler has to enforce at runtime that no
> exception leaks out of the function. It basically has to enclose the
> whole function with a catch(...) and terminate (threw std::unexpected
> ()) if it catches anything. Not very useful.

I'm not talking about throw() as specified today, I
was envisioning a reasonable use-case for a statically
checked exception specification - let's name it as
"throw() static" or some such. This envision would
*not* use a runtime check, but all inner function
calls would recursively need to fulfill the same
"throw() static" to make the code well-formed.

Greetings from Bremen,

Daniel Krügler

Brendan

unread,
Nov 21, 2008, 11:43:50 PM11/21/08
to
On Nov 21, 3:57 pm, Eugene Gershnik <gersh...@gmail.com> wrote:
> On Nov 21, 5:20 am, marlow.and...@googlemail.com wrote:
> Apart from the above the main complaint about statically checked
> exceptions seems to be that they propagate forcing one to revisit the
> entire calling chain when modifying low-level code. This is considered
> a nuisance (just like with const) and bad programmers commonly resort
> to swallowing everything (or casting const away). This problem is real
> but the reason for it is not the exception specifications but
> programmers misunderstanding of what they are for. People who
> encounter this problem invariably use the following way of designing
> their function interfaces:
>
> - write the implementation
> - see what exceptions propagating out of the function compiler
> complains about
> - declare them in function interface
> - repeat the process for any implementation change
>
> The problem with this approach is that it is completely backwards.
> Static exception specification is a part of a function interface. It
> has to be designed upfront (just like argument types and constness
> are). If the implementation 'wants' to emit an exception that is not
> supported by the interface you either have a design problem or should
> convert the low-level implementation exception into the higher-level
> exception declared in your interface.

I agree, exception specifications in Java are unjustly maligned. They
are a means of stating that certain exceptions are part of the
interface of a method, and forcing clients to handle them. They would
fit in well with a language that focuses on static correctness
verifiation (whether Java is one of those languages is an open
question), but not with a dynamic language like Python that only check
correctness of operations at runtime.

The real problem with exceptions in Java is that most programmers suck
at using exceptions. Even good programmers usually have no idea what
to do when an exception is thrown. The answer to that question is
usually: Nothing

Let the program terminate unless there really is something you can do
to recover. Usually, the most you want to do is log, and rethrow the
exception or call exit. The whole point of exceptions is that they
kill the program instead of letting errors go unnoticed.

Putting error handling code in for an error you can't really handle is
pointless cruft.

Checked exceptions on the other hand represent a middle ground between
totally unexpected events, and non-exceptional events. They are still
exceptional, but common enough to be part of the function interface.
Most importantly, checked exceptions are *recoverable*. You can safely
keep running your process after one is picked up without fear of
having broken an invariant or corrupted memory. A good example of a
checked exception is "file not found" when trying to open a file. A
good example of an unchecked exception is "null pointer error" or "out
of memory error." You might conceivably recover from those in some
rare cases, but not often enough for handling logic to be part of the
function interface.

In C++ in contrast to java, exception specifications *are* really
horribly broken though. The most widely used C++ compiler doesn't even
both to implement them. Here's why the are broken:

1. There is no checked/unchecked exception distinction. Exception
specifications are an all or nothing proposition. You can't say: "you
always need to handle the possibility of 'file not found', but we'll
leave it up to the client whether to handle 'file descriptor quota
reached'"

This is really important, because if you try to throw an exception
that's not part of the specification, you still need it to be
handleable to the 1% of the clients that actually can handle it. In C+
+ this is impossible because the specication mechanism verifies
correctness at *runtime* and kills the process if you try to leak an
unspecified exception to the caller.

This brings us to the other problem.

2. Exception specification's exist at runtime in C++, which is stupid
because they are an element of static program verification. This is
like types with no virtual members having a v-table and doing all
member function lookups through it. It's pointless and totally
contrary to the fat free design of C++.

I'm not a big fan of Java... actually I think it is an awful language
in terms of things like its type system, which can't seem to decide
whether it is static or not, and thus presents us with the worse of
both worlds. However, this is one area where Java did it right and C++
screwed up.

On the plus side, since no one actually *uses* exception
specifications in C++, it wouldn't be that hard to fix them. The
standard could simply deprecate them, and in a few years add them back
with fixed semantics, kind of like what happened to auto.

Brendan

Brendon

unread,
Nov 23, 2008, 4:16:07 AM11/23/08
to
I am the author of a program called EDoc++: http://edoc.sourceforge.net/

The goal of EDoc++ is to attempt to alleviate many of the issues
associated with using exceptions in C++. EDoc++ is capable of
statically asserting exception specifications are met. However even
with this feature i think that exception specifications are largely
useless in C++. I also agree with the authors that exception
specifications as defined in other languages like Java have many
issues.

Two of the main uses i see for exception specifications are:


Documentation

C++: Exception specifiers are rarely used and as a result provide
little if no documentation about exception propagation. If exception
specifications are provided, then they must be complete or risk
causing the application to terminate. The task of achieving this is
quite difficult.

Java : Statically asserting *SOME* exceptions as Java does means that
exception specifications provide *better* documentation. Again
however, it does not provide information about runtime exceptions as
they are not statically asserted by the compiler (and should not be in
my opinion).

EDoc++ : Can generate the *COMPLETE* list of exceptions propagating
from out of a given function. Not only that but it can also provide
information on the entry point of the and where it originates from.
Such documentation does not need to be manually maintained and does
not affect the runtime of the application.


Forced change analysis

C++ : Forced change analysis does not really exist in C++ as C++
dynamically asserts the exception specifications. If exception
specifications were used in C++ to help with this, then it would have
to be performed manually (I.e. Check EVERY function and see if the
exceptions it can throw) and it is dangerous if you miss an exception
(terminates the program).

Java : This is partially enforced every time you compile Java code.
I.e. If you change a function so that it throws a new type of
exception then you will be forced to also look at all functions that
call it when you compile them.
There are a few problems with the way Java does this. One such problem
is that if a function throws an exception, it is quite rare that other
functions which directly call it need to know the details about those
exceptions. Rather, the direct callers often need to know just that
they behave well in the presence of exceptions (exception safety
guarantee) and that someone further up the call stack will handle the
exception. So often you have this cascade affect of just adding an
extra exception to the specifier of a lot of functions that really do
not care about the exception when you update code for an existing
function to throw a new exception. It is really only the throw site
and the catch site that need to know the details about the exception,
all other code just needs to know does the function meet the nothrow,
strong, basic or no exception guarantee.

EDoc++ : Currently this does not support any form of change analysis
unless you make use of exception specifiers. However i have plans of
adding a form of markup that effectively allow you to define exception
safety guarantee specifications instead of exception specifications.
Basically using EDoc++ i want a coder to be able to markup their code
to indicate that a given function meets a given guarantee and also
optionally associate some requirements to that that can be enforced
statically. This way the guarantee is defined in the code and a static
assertion is generated when that guarantee is not met or changes. I.e.
Calling functions want to be looked at when the functions they call do
not meet the requirements they were written to any more.

Bart van Ingen Schenau

unread,
Nov 23, 2008, 9:36:09 AM11/23/08
to
Eugene Gershnik wrote:

> The problem with this approach is that it is completely backwards.
> Static exception specification is a part of a function interface. It
> has to be designed upfront (just like argument types and constness
> are). If the implementation 'wants' to emit an exception that is not
> supported by the interface you either have a design problem or should
> convert the low-level implementation exception into the higher-level
> exception declared in your interface. When using such approach the
> long chains of exception specification propagation disappear. Any
> change in low-level implementation that causes a new exception to be
> thrown is quickly handled and translated into some higher-level
> exception a few caller levels above it. And once in a while you do
> discover serious design problems when you find that you cannot
> reasonably translate.

That sounds all very nice in theory, but it suddenly breaks down when
part of the functionality of your class will be provided by the
clients, either in the form of a derived class or a template argument.

I challenge you to design a generic resizeable container class (ala
std::vector) with full exception specifications.
The container must be able to efficiently hold a sequence of a type of
my choosing. I don't know yet which exceptions this type may throw from
its constructor.

>
>> But as I moved in to java and saw the effects mentioned by Ekcel I
>> decided to prefer runtime checks in java and to not bother at all in
>> C+ +.
>
> I would recommend you give it another try. Write exception
> specifications upfront based on function semantics without much regard
> to implementation details and see if those effects disappear.
>
> --
> Eugene
>
>

Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://c-faq.com/
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/

Thomas Beckmann

unread,
Nov 24, 2008, 10:02:09 AM11/24/08
to
>> I disagree. C++ exception specification can be statically checked in
>> exactly the same way as function types are checked - since they are
>> (or should be) available on declarations of functions in the header,
>> the compiler has them available at all times. There is no requirement
>> for "reflection" or other similar runtime type metadata provider to
>> implement checked exceptions.
>
> The compiler certainly does not have every header in a system
> available at all times, nor should it. Most well factored libraries
> will use so-called private headers, and these signatures are not
> available (by design) to the client code.

For every function called by client code there must be a prototype.

> Lets see what happens:
> In a cpp. file, we include headers for three libraries that do the
> same thing. This generates a binary for a dynamic link library. So not
> only the compiler does not know, but the linker as well does not know
> at build time. We only find out at runtime:
> #include <liba.h>
> #include <libb.h>
> #include <libc.h>
> void mywrapper(T arg){
> if(use_liba)
> liba::process(arg)//may throw a liba:exception
> else if(use_libb)
> libb::process(arg)//may throw a libb:Exception
> else
> libc::process(arg)//may throw a libc:error
> //of course, we are also using std::, which can throw std::exception
> }
> (for a real world example of this sort of thing, look at the QuickFix
> library, which uses exception specification + multiple XML parsers. )

All 3 process() variants must list exception in their prototypes. At compile
time of mywrapper() the exception specification of all these process()
functions can be statically checked against the specification on
mywrapper().

> The header has no knowledge of the three libraries:
> void mywrapper(T arg);

It does not need to since mywrapper() must declare its exceptions in its
header. Consistency was checked for at compile-time of mywrapper().

> The exception specification in the header declaration either:
> 1. Has to list every exception thrown by each library, which breaks
> encapsulation, which is the entire point of mywrapper

I do not see how this breaks encapsulation. If I say open_file()
throws(file_exception) the throws spec belongs to the prototype in much the
same way as the function name or its list of parameters. Also exceptions are
just another way of error reporting, so you argument would apply equally
well when listing possible error codes in the documenation or as an enum.

> 2. Implement mywrapper to catch every possible exception, and convert
> it to a type to match the exception spec. This is extremely tedious
> and error prone – if you don’t get it right, BOOM your app terminates
> by default. No one want to use mywrapper then.

Again, error codes must be dealt with anyways. Also you need to convert them
in much the same way. Static checking would eliminate the "terminate by
default" you mentioned above, since exception specifications were checked at
compile-time a program containing broken exception handling simply would be
rejected by the compiler.

> 3. let mywrapper emit any exception, and let the catch point deal with
> it.

Depends on the degree of error fixing you can accept. Do you think its
really so uncommon to write stuff like:

int err = MyFunc();
if(err)
return err; // RAII cleans up for us...

???

My guess is, this kind of error processing is in the vast majority.

> None of the above is particularly appealing, however, after much trial
> and error number three is the most workable. Encapsulation is not
> broken if catch(…) is used, there are no tedious exception conversion
> routines, and the exception is handled at place designed to deal with
> exceptions.

Well checked exceptions would add much value to maintainability. Imaging
what happens in the code I listed above when MyFunc() is extended and may
result in additional errors to be generated. Would not it be advantageous
when the compiler says: hey in TestFunc() you call MyFunc() but do not react
on error X?

> Of course, the client is probably catching using catch(…) which
> trashes some hopefully useful diagnostic info. But the system is still
> correct, reliable, and encapsulated. If that diagnostic info is
> needed, well, then something has to give, but exception specs don’t
> help with this.

How do you know the code is okay when catch(...) is used and I modify stuff
under the hood? If its really just error reporting by some message box in
the GUI layer then there is nothing to prevent you from specifying
throws(...) and catch(...).

> I really thought they did at one point, and used them religiously,
> until they themselves became the major source of system unreliability.
>
> In any case, and A Marlow points out, what if mywrapper were a
> template? Such that
> template <class A>void mywrapper(T arg){
> A::process(arg);
> }
> There is no possible way for the template author to provide mywrapper
> with an exception specification. For static checking to work, the
> compiler would have to keep up with the exception spec used for process
> (), and somehow the template “inherits” this spec. Not too hard for my
> one line example, but consider
>
> template <class A, class B, class C, class D >void mywrapper(T arg){
> D::foo(C::bar(arg?B::tricky():A::process(arg)));
> }
> I suppose that mywrapper could automatically spec the union of the
> unholy mess of exception specs, however, there is no programmer who is
> ever going to write catch blocks for each case and get it right, even
> if they could get info on what the generated exception spec is.

Certainly, you could make the throws() specification of mywrapper() depend
on the template arguments. There some typedefs, traits, etc. could be
provided. I did not think this trough but come up with it in 5min. The point
is there are ways to solve this.

> To drive this home, one thing that C++ has that Java does not, is
> operator overloading. They can throw as well. Sigh.

So, were is the problem? Operators are resolved at compile-time, same as
orinary functions.

> Or something like
> streams, where you can turn exceptions on and off, and indeed, through
> some trickery, throw them at a later time. How would a static spec
> handle that?

It would not be handled. Why would you turn off exceptions in the first
place? Either remove that "feature" or make it configurable at compile-time.
I consider this design to be broken however.

Why can not I have stack traces in C++? The debugger shows them....

> Also realize that much of the standard library was designed when there
> were very few compilers that actually supported exceptions. The same
> story applies for things like member templates, partial specialization
> and the like. Around this same time (mid 1990’s) there was much
> concern that it was impossible to actually design exception-safe
> templates. This of course was proven wrong, but the standard libs were
> finalized not long after that.
> There was a natural tendency to replace the standard C library return
> codes with exception types (which is why we have exceptions of those
> types) and use them for preconditions just like they were used in the
> C library. However, exceptions are not generalization of return code,
> but rather generalizations of longjmp. When people start thinking that
> C++ exceptions == return codes, then they are bound to be
> disappointed. Java takes the “exception is a generalized return code”
> point of view however, and adds in support, as you say, for long
> distance jumps.

When writing solid code that checks EVERY error condition and every return
code then you get a robust program. Even the simplest tasks take way too
many lines in C++ if you do this. Why not take advantage of exceptions for
error codes?

Java has a garbage collector so there are no dtors; C++ has RAII so there
are no finally statements. These are competing concepts. In the example you
gave, if f.open() would throw you would not need your if(!f) throw line in
the first place. With checked exceptions one then can state: I am aware of
open() throwing stuff at me and I checked that I operate correctly even in
this context.

For this to be practical we need compile-time checked exceptions.


Regards,
Thomas.

Richard Corden

unread,
Nov 25, 2008, 10:09:08 AM11/25/08
to
Hi,

Bart van Ingen Schenau wrote:
>
> That sounds all very nice in theory, but it suddenly breaks down when
> part of the functionality of your class will be provided by the
> clients, either in the form of a derived class or a template argument.
>
> I challenge you to design a generic resizeable container class (ala
> std::vector) with full exception specifications.

I don't think this is a fair challenge. Let me try one on you:

I challenge you to design a generic resizeable container class (ala

std::vector) which doesn't use dynamic memory and doesn't require
copying of it's elements.


As with any feature there are trade-offs. In the design of vector, it
was decided that elements needed to be copyable. This allowed for other
optimisations in the design. Similarly, if we want to have a vector
with full exception specifications then it does not seem unreasonable
that there should be an additional requirement on the element type.

The requirement might be something such as the exception needs to derive
from "std::exception" - which probably isn't that bad anyway.


Regards,

Richard

--
Richard Corden

Nevin :-] Liber

unread,
Nov 25, 2008, 11:16:15 AM11/25/08
to
In article <gg943d$ehq$1...@online.de>,
"Thomas Beckmann" <ka655...@online.de> wrote:

> > 3. let mywrapper emit any exception, and let the catch point deal with
> > it.
>
> Depends on the degree of error fixing you can accept. Do you think its
> really so uncommon to write stuff like:
>
> int err = MyFunc();
> if(err)
> return err; // RAII cleans up for us...

> My guess is, this kind of error processing is in the vast majority.

But that is the moral equivalent of no exception specifications (don't
know or care about the kind of error; just pass it up the chain). If
more checking is desirable, the code should look more like:

int err = MyFunc();
switch (err)
{
case NoErr:
break;
case ConditionOne:
case ConditionTwo:
//...
case ConditionN:
return err;
default:
unexpected();
}

Yet, since people don't usually write code like this, yours is actually
an argument against exception specifications.

> Well checked exceptions would add much value to maintainability.

I'd say less. The problem is all that all the intermediate functions
between the throw and the catch now have to know about all the possible
exceptions just so they can ignore them.

> Certainly, you could make the throws() specification of mywrapper() depend
> on the template arguments. There some typedefs, traits, etc. could be
> provided. I did not think this trough but come up with it in 5min. The
point
> is there are ways to solve this.

This has been one of the outstanding issues with exception
specifications for years. If you have new insight on how to solve this,
I'm quite sure many of us would be very interested in hearing about them.

> When writing solid code that checks EVERY error condition and every return
> code then you get a robust program.

But not every single function needs to have the knowledge about every
possible error condition. For many, it is good enough to know that an
error has occurred and it is time to clean up before passing the error
upstream to something which can handle it. In my coding style, calling
the destructors during stack unwinding to do cleanup no matter how the
function was exited (exception or return) suffices in the vast majority
of cases.

--
Nevin ":-)" Liber <mailto:ne...@eviloverlord.com> 773 961-1620

Eugene Gershnik

unread,
Nov 25, 2008, 3:51:51 PM11/25/08
to
On Nov 23, 6:36 am, Bart van Ingen Schenau <b...@ingen.ddns.info>
wrote:

> Eugene Gershnik wrote:
>
> That sounds all very nice in theory, but it suddenly breaks down when
> part of the functionality of your class will be provided by the
> clients, either in the form of a derived class or a template argument.

First of all let's separate derived classes (and virtual function
interfaces in general) from generic code in the sentence above.

With regards to generic code you are right but this is a deficiency of
the syntax not some fundamental problem. To make generic types work
with static exception specifications one needs to be able to say
something like "throws the same types as are thrown by...".
This is fundamentally not very different from being able to say
"returns a type dependent on the type of ..." which is taken for
granted these days. (And which is BTW still impossible in Java).

Using some imaginary syntax:

template<typename T>
void container<T>::insert(const T & val) static_throw(emitted_by(T
(val))

where emitted_by is a compile-time expression giving a typelist of
types that an expression can throw.

Now, with regards to virtual function interfaces there is no issue
even today in Java. If you design an interface you specify what
exceptions can be emitted from it. This is a part of the interface
just like return types are. An implementation will have to conform to
this interface and either wrap or translate different exception types
it produces. Of course there are plenty of badly designed interfaces
out there but then there are plenty of badly designed interfaces with
regards to return values or parameter types too.

> I challenge you to design a generic resizeable container class (ala
> std::vector) with full exception specifications.

Assuming something like static_throw(emitted_by(...) syntax above this
task becomes rather trivial (I think). Note that AFAICS supporting
such syntax wouldn't require any special magic from the compiler. If
it supports static exception specifications it already knows what any
expression involving T can throw.

--
Eugene


--

Gerhard Menzl

unread,
Nov 25, 2008, 4:55:30 PM11/25/08
to
Thomas Beckmann wrote:

> Java has a garbage collector so there are no dtors; C++ has RAII so
> there are no finally statements. These are competing concepts.

Non sequitur. Garbage collectors take care of memory, but destructors
have much wider responsibilities. Hence the presence of a garbage
collector does not eliminate the need for destructors.

--
Gerhard Menzl

Non-spammers may respond to my email address, which is composed of my
full name, separated by a dot, followed by at, followed by "fwz",
followed by a dot, followed by "aero".

Martin T.

unread,
Nov 25, 2008, 4:56:13 PM11/25/08
to
Thomas Beckmann wrote:
>...

>> And yes the standard library uses them to signal precondition
>> violations. The point was that debugging a program that uses C++
>> exceptions to protect preconditions is very difficult. (The MSVC
>> debugger does an excellent job in this regard though). The Java
>> exceptions seemed esp designed to provide stack traces, making them
>> far easier to use in spotting precondition violations.
>
> Why can not I have stack traces in C++? The debugger shows them....
>

Shame that. Used to think that too. :)
However, at runtime of release code, there is no symbolic information
anymore and all a stacktrace could provide would be a bunch of
addresses. (Well you can use these for post mortem analysis from a
core-dump, but not during runtime to get any useful info.)
Oh. And if you have optimized code the stack trace might not even be
useful then, since it does no longer correspond to the logical stack of
the code ... (Well, at least on MSVC - and that debugger seems to be
quite good - debugging optimized code is horrible.)
While it would be nice I don't think it would be possible without rather
fat standardized reflection features for C++ and we're simply not going
to get these, imho.

br,
Martin

Bart van Ingen Schenau

unread,
Nov 25, 2008, 5:00:58 PM11/25/08
to
Richard Corden wrote:

> Hi,
>
> Bart van Ingen Schenau wrote:
>>
>> That sounds all very nice in theory, but it suddenly breaks down when
>> part of the functionality of your class will be provided by the
>> clients, either in the form of a derived class or a template
>> argument.
>>
>> I challenge you to design a generic resizeable container class (ala
>> std::vector) with full exception specifications.
>
> I don't think this is a fair challenge. Let me try one on you:
>
> I challenge you to design a generic resizeable container class (ala
> std::vector) which doesn't use dynamic memory and doesn't require
> copying of it's elements.

Challenge accepted.
The container will have an internal buffer of SIZE_MAX bytes, into which
the elements will be move-constructed.
It will not be possible to add more than one element at a time, and the
user should make a copy if they want the original object that is added
to the container to be preserved.

>
> As with any feature there are trade-offs. In the design of vector, it
> was decided that elements needed to be copyable. This allowed for
> other
> optimisations in the design. Similarly, if we want to have a vector
> with full exception specifications then it does not seem unreasonable
> that there should be an additional requirement on the element type.
>
> The requirement might be something such as the exception needs to
> derive from "std::exception" - which probably isn't that bad anyway.

Which would make the container unusable with types from third-party
libraries that don't have their exception hierarchy rooted in
std::exception,
and it does not buy you anything in terms of statically checking
exception specifications. The empty specificantion is just replaced
with a 'throw(std::exception)' and you are still no wiser if all
possible exceptions are actually handled.

>
>
> Regards,
>
> Richard
>

Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://c-faq.com/
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Nevin :-] Liber

unread,
Nov 26, 2008, 1:55:26 PM11/26/08
to
In article
<a7a665ad-87da-4319...@v5g2000prm.googlegroups.com>,
Eugene Gershnik <gers...@gmail.com> wrote:

> where emitted_by is a compile-time expression giving a typelist of
> types that an expression can throw.

Why is this typelist any better in practice than not having exception
specifications? I just don't see people writing a TMP to make sure that
they have handled every possible exception.

> Assuming something like static_throw(emitted_by(...) syntax above this
> task becomes rather trivial (I think).

It looks like I need to specify my program twice. Even with just a
simple templated variable, all my code will have to look like:

template<typename T>
struct Foo
{
T t;

void DoSomethingThatUsedToBeSimple()
emitted_by(static_cast<bool>(t); ++t)
{ if (t) ++t; }
};

That is one heck of a programming burden.

--
Nevin ":-)" Liber <mailto:ne...@eviloverlord.com> 773 961-1620

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Karl Uppiano

unread,
Nov 26, 2008, 1:59:21 PM11/26/08
to
"Bart van Ingen Schenau" <ba...@ingen.ddns.info> wrote in message
news:1282390.e...@ingen.ddns.info...
> Richard Corden wrote:

[...]

>> As with any feature there are trade-offs. In the design of vector, it
>> was decided that elements needed to be copyable. This allowed for
>> other
>> optimisations in the design. Similarly, if we want to have a vector
>> with full exception specifications then it does not seem unreasonable
>> that there should be an additional requirement on the element type.
>>
>> The requirement might be something such as the exception needs to
>> derive from "std::exception" - which probably isn't that bad anyway.
>
> Which would make the container unusable with types from third-party
> libraries that don't have their exception hierarchy rooted in
> std::exception,
> and it does not buy you anything in terms of statically checking
> exception specifications. The empty specificantion is just replaced
> with a 'throw(std::exception)' and you are still no wiser if all
> possible exceptions are actually handled.

Perhaps "std::exception" is a bad example. In your example, your constructor
could throw a creation_exception directly, or extend it for more granularity
if desired. Obviously, it would be desirable if the container and the
contents were developed together with exceptions in mind from the outset.
Legacy compatibility is a separate issue, and if that were a requirement, of
course it would add constraints. One possible work-around would be for the
container to catch(...) from legacy constructors and throw a generic
creation_exception in that case.

My work requires that I move freely and frequently between Java and C++.
That has influenced my C++ coding style. Having seen "exceptions done
right", I now use exceptions in C++ with far more regularity than I used to.


--

red floyd

unread,
Nov 26, 2008, 2:03:05 PM11/26/08
to

I used to have a class like this:

class stack_trace
{
private:
static stack_trace* call_stack_;
stack_trace* next_;
const char* where_;
stack_trace();
stack_trace& operator=(const stack_trace&);
stack_trace(const stack_trace&);
public:
stack_trace(const char *where)
: where_(where)
{
next_ = call_stack_;
call_stack_ = this;
}
~stack_trace()
{
call_stack_ = call_stack_->next;
}
static void dump_stack(std::ostream& os = std::cout)
{
for (stack_trace* p = call_stack_; p != NULL; p = p->next_)
os << p->where_ << "\n";
}
}
stack_trace* stack_trace::call_stack_ = NULL;

Then I could declare a stack_trace variable wherever I needed.

E.g.:

void f()
{
stack_trace("f");

Richard Corden

unread,
Nov 27, 2008, 11:19:46 AM11/27/08
to
Hi,

Bart van Ingen Schenau wrote:
> Richard Corden wrote:
>
>> Hi,
>>
>> Bart van Ingen Schenau wrote:

>>>
>>> I challenge you to design a generic resizeable container class (ala
>>> std::vector) with full exception specifications.
>> I don't think this is a fair challenge. Let me try one on you:
>>
>> I challenge you to design a generic resizeable container class (ala
>> std::vector) which doesn't use dynamic memory and doesn't require
>> copying of it's elements.
>
> Challenge accepted.
> The container will have an internal buffer of SIZE_MAX bytes, into which
> the elements will be move-constructed.

You've had to exchange one compromise, that of dynamic memory, with
another, that of a maximum size. Your solution is a good one within the
set of constraints that you were given.

Adding the constraint of exception specifications changes the
constraints on the element type in the vector - but it doesn't mean that
that vector is somehow "wrong". If that was the case, then we could
argue that a vector which has a maximum size is also "wrong".


[...]


>> The requirement might be something such as the exception needs to
>> derive from "std::exception" - which probably isn't that bad anyway.
>
> Which would make the container unusable with types from third-party
> libraries that don't have their exception hierarchy rooted in
> std::exception,

Yes. In the same way that 3rd party types that are not copyable cannot
be used in std::vector today. It is just a different constraint on that
vector. However, why not have 2 vectors, one that's checked when you
know exactly what your element type throws, and one where you don't.


> and it does not buy you anything in terms of statically checking
> exception specifications. The empty specificantion is just replaced
> with a 'throw(std::exception)' and you are still no wiser if all
> possible exceptions are actually handled.

Static checking would be able to identify a copy constructor that has no
exception specification, or one that explicitly states that it throws
say "int". It would also protect you in the cases where you
accidentally called a member function of the vector from a function with
a "throw()" spec.


If a 3rd party library is being used in a project, then the client of
that code *should* know what can be thrown.

There is always the choice to use the current std::vector or they might
use a checked vector. Such a new vector type could use variadic
templates to allow the specification of the types that the element type
actually throws!

std::spec_vector<A, int, char /* throws int and char */> v;


The real problem today is that there is no checking at all. In current
C++ if you use exception specifications and get it wrong, then your
program can simply die horribly. Without static checking - the only
safe option is to avoid specifications completely.


Regards,

Richard

--
Richard Corden

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Eugene Gershnik

unread,
Nov 27, 2008, 11:27:47 AM11/27/08
to
On Nov 26, 10:55 am, "Nevin :-] Liber" <ne...@eviloverlord.com> wrote:
> In article
> <a7a665ad-87da-4319-9fd6-1e1c7fcbd...@v5g2000prm.googlegroups.com>,

> EugeneGershnik<gersh...@gmail.com> wrote:
>
> > where emitted_by is a compile-time expression giving a typelist of
> > types that an expression can throw.
>
> Why is this typelist any better in practice than not having exception
> specifications? I just don't see people writing a TMP to make sure that
> they have handled every possible exception.

This is a very common misunderstanding. The purpose is emphatically
*not* to make sure you handle every possible exception. It is to
actually allow you to handle *some* exceptions.
Consider this simple line of code

int i = foo(42);

Suppose you wanted to handle some recoverable errors that could be
reported by foo. Handle here does not mean "log and abort on every
error" but rather to do something that may depend on exception type/
error code. For example if foo reports network failure you might want
to reconnect to the server. If it reports out of memory condition you
might want to clean some caches etc.
Note that you don't want and *cannot* handle *every* possible error.
If there is a bug in foo implementation and it throws logic_error or
some such then "let it safely propagate to the top level, then log and
abort" is the appropriate response. IOW you care only about certain
"rare but not completely unexpected" errors, not every possible error
that might ever happen.

So how do you do that today? You go and read foo's documentation
(which somebody had to write in the first place). You trust that it is
accurate and is not going to change and wrap the call to foo is try/
catch block to handle errors you want to handle.
This is all completely manual and compiler will never help you there.
This immediately produces all the disadvantages of things not enforced
by a compiler. Even assuming docs exist and are accurate, if the foo's
author changes its implementation in version 2 compiler will not alert
you about new possible "rare but not completely unexpected" error that
you might want to handle. It will not alert the author himself that
the docs might need to be changed or some exceptions translated
internally in order to conform to the published doc. Etc. etc.

What compile-time exception specifications give you is an ability to
have the compiler check the same things that you would have to put in
the docs and verify manually *anyway*. Except of course most people
don't put this (or any other information about exceptions) in their
docs. You have to look at the source code, reason about all possible
implementations and hope for the best. This doesn't matter for
applications where the usual "log and abort on any error" is good
enough. But it does matter for those that need to write reliable code.


> > Assuming something like static_throw(emitted_by(...) syntax above this
> > task becomes rather trivial (I think).
>
> It looks like I need to specify my program twice. Even with just a
> simple templated variable, all my code will have to look like:

[...]

> void DoSomethingThatUsedToBeSimple()
> emitted_by(static_cast<bool>(t); ++t)
> { if (t) ++t; }

[...]

> That is one heck of a programming burden.

You have the worse burden right now. For this same function don't you
have to write in your docs/comments something along the lines:

"Exceptions: can throw whatever is thrown by expressions
static_cast<bool>(t) and ++t."

This will have to be more verbose and harder to maintain than whatever
you say to the compiler. Of course you might not write this in your
docs but that only proves my point.
To put it more succinctly (I hope):
If there is some information about interfaces that you always must
specify in your documentation it ought to be verified and enforced by
the compiler, not programmer.

--
Eugene

Bart van Ingen Schenau

unread,
Nov 27, 2008, 11:29:58 AM11/27/08
to
Karl Uppiano wrote:

The big problem here is that templates (especially template *libraries*)
are NOT developed together with the client code.
And I don't consider interoperability with other libraries to be a
legacy issue, especially if you start requiring clients of your
template to throw specific exceptions.

As for turning client-specific exceptions into a generic
creation_exception, I don't like throwing away information that my
client might want to have, simply because I have an overly strict
exception specification to meet.

Additionally, how do you like adding useless try-catch blocks to keep
the compiler happy, because you know that my_container<int> will never
ever throw a creation_exception, but the compiler doesn't.

>
> My work requires that I move freely and frequently between Java and
> C++. That has influenced my C++ coding style. Having seen "exceptions
> done right", I now use exceptions in C++ with far more regularity than
> I used to.

Before people start to misunderstand me, I am not opposed to using
exceptions. In fact, I think they are a wonderful tool.

It is the use of exception *specifications* that I have issue with.
There are just too many unsolved fundamental issues left for me to use
or advocate them.
Some of those issues also exist in Java, and the typical way that I have
seen them solved is to ignore the error (catch the exception without
and kind of handling). Sometimes that might be the correct reaction,
but if it happens to all exceptions that the base-class/interface
version of the function does not mention in the exception
specification, then it becomes suspicious.

Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://c-faq.com/
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Thomas Beckmann

unread,
Nov 27, 2008, 11:58:33 PM11/27/08
to
>> > 3. let mywrapper emit any exception, and let the catch point deal with
>> > it.
>>
>> Depends on the degree of error fixing you can accept. Do you think its
>> really so uncommon to write stuff like:
>>
>> int err = MyFunc();
>> if(err)
>> return err; // RAII cleans up for us...
>> My guess is, this kind of error processing is in the vast majority.
>
> But that is the moral equivalent of no exception specifications (don't
> know or care about the kind of error; just pass it up the chain).

Yes, its common practice and I am no fan of that:
1. three lines where one should suffice, and
2. way too general.
Unchecked exceptions solve the first issue only.

Bytheway, C-style checking often mixes up kind and location of error. I have
seen -1, -2, -3... with semantics being error at first if statement going
wrong, error at second if statement... Not only its handed upwards making
the locational aspect useless, but there is also no way to react on it since
there is no semantics. Why not use error codes of type "const char*", at
least one can print them with ease.

In many cases I try to follow the rule of one-X one-purpose, where X can be
method, class, package... Doing so often allows a boolean error code for
worked or didn't.

> If more checking is desirable, the code should look more like:
>
> int err = MyFunc();
> switch (err)
> {
> case NoErr:
> break;
> case ConditionOne:
> case ConditionTwo:
> //...
> case ConditionN:
> return err;
> default:
> unexpected();
> }
>
> Yet, since people don't usually write code like this, yours is actually
> an argument against exception specifications.

Well, listing all codes is not necessary if you have a way of grouping, i.e.
exception hierarchies.
The default case above I'd state as:
default:
// this should not happen
assert(false);
reboot(embeddedDevice);
And I'd prefer the compiler telling me this is a possible code path rather
than at runtime run into this. This style comes in my list just after class
Helper { /*TODO: design me!*/ }...

What options do I have in the default case? I can not write any meaningful
code there since the error condition is not even defined at the time of
writing. Also I can not leave the default since then newly introduced
condition codes would get through undetected.

>> Well checked exceptions would add much value to maintainability.
>
> I'd say less. The problem is all that all the intermediate functions
> between the throw and the catch now have to know about all the possible
> exceptions just so they can ignore them.

There's nothing to stop you from grouping exceptions in a hierarchy and
state a throws for a group of exceptions.

>> Certainly, you could make the throws() specification of mywrapper()
>> depend
>> on the template arguments. There some typedefs, traits, etc. could be
>> provided. I did not think this trough but come up with it in 5min. The
> point
>> is there are ways to solve this.
>
> This has been one of the outstanding issues with exception
> specifications for years. If you have new insight on how to solve this,
> I'm quite sure many of us would be very interested in hearing about them.

Agreed, this is the hardest part. However, there are languages out there
that have both checked exceptions and generics. Now I know generics are not
templates but their differences are irrelevant for this discussion.

Since most template stuff requires the implementation to be visible at
compile-time, the compiler could provide some form of deduction of possible
exceptions a template function can possibly emit. Maybe the compiler could
take the user supplied throws specification and eliminate all exception
types the actually generated implementation does not throw. This leaves
either a subset of exception types the instantiation can spit on the callee,
or reveales a potential bug when the deduced exceptions violate the throws
spec.
As I see it checked exceptions provide a means of stating what error
conditions I was aware of at the time I wrote or revised the code.

>> When writing solid code that checks EVERY error condition and every
>> return
>> code then you get a robust program.
>
> But not every single function needs to have the knowledge about every
> possible error condition. For many, it is good enough to know that an
> error has occurred and it is time to clean up before passing the error
> upstream to something which can handle it. In my coding style, calling
> the destructors during stack unwinding to do cleanup no matter how the
> function was exited (exception or return) suffices in the vast majority
> of cases.

I try hard doing so as well. This is an implementation detail however. A
functions public interface consists of the prototype (syntax) and
documenation (semantics). Error conditions are part of it too but can be
documented as a comment or written explicitly as checked exceptions...


--

Thomas Beckmann

unread,
Nov 27, 2008, 11:52:12 PM11/27/08
to
Thanx for your reply. Actually, I find this GC vs. Dtor stuff quite
interesting and thought a while about it.

>> Java has a garbage collector so there are no dtors; C++ has RAII so
>> there are no finally statements. These are competing concepts.
>
> Non sequitur. Garbage collectors take care of memory, but destructors
> have much wider responsibilities. Hence the presence of a garbage
> collector does not eliminate the need for destructors.

Absolutely correct, I did not say otherwise,
1. Garbage collection does not eliminate the need for resource management,
i.e. Dispose Pattern of C#, Close methods in Java,... This is since GCs
reclaim memory only (Maybe a limitation of current technology?)
2. Destructors need to be executed deterministically by design, thus they
can not be supported in a garbage collecting environement, i.e. C#/Java have
finalizers and no dtors.

A dtor must run exactly at the end of the scope to be of use. As a result
supporting dtors eliminates the need for a GC as the dtor "knows" exactly
when to reclaim memory. Approximating this sequence point is the mission of
GC algorithms. In conclusion, garbage collection implies dtors are not
supported, since a GC does not run deterministically. Finally is a work
around for this lack of dtors. In all cases a finally clause can be
transformed into a dtor unless you have no dtors in the runtime, thats why I
meant C++ doesn't need no finallies.

In summary,
if there is a GC you have no dtors, and
if you have dtors you need no finallies...


--

Brendan

unread,
Nov 27, 2008, 11:51:02 PM11/27/08
to
On Nov 25, 2:00 pm, Bart van Ingen Schenau <b...@ingen.ddns.info>
wrote:

This is a non-argument. Containers are only compatible with types
designed to be compatible with them, that goes without saying. The
standard containers don't work with many types, including those
without copy constructors, those without relational operators (you
can't just stick a pointer in a map), etc. You only need an adapter if
you want incompatible types to work together.

> and it does not buy you anything in terms of statically checking
> exception specifications. The empty specificantion is just replaced
> with a 'throw(std::exception)' and you are still no wiser if all
> possible exceptions are actually handled.
>

This has already been gone over in this thread a number of times.
Everyone agrees that C++ exception specifications are broken, so
attacking defficiencies in the C++ implementation of C++
specifications does not constitute a valid complaint against exception
specifications in general.

C++ exception specifications apply to *all* types of exceptions, so
you have the problem of client code being forced to know about
exceptions that it doesn't need to know about, or of specifying a root
exception type, which is the same thing as having no exception
specification.

The only language where exception specifications are widely used,
Java, has both checked and unchecked exceptions. Only exceptions that
client code *should* really know about need be specified. Most
exceptions don't fall into this category. Nearly every function can
throw an "out of memory" exception, but you almost never want to
handle it, and specifying it for every method would be a pain.
Exception specifications exist for the case where the exception is a
part of the interface to a function in the same way that a return
value or an out parameter is a part of the interface. That people use
exception specifications for other kinds of exceptions merely means
that they don't get the exception specification concept, not that
there's something wrong with the idea of an exception specification.

Really, I think that a C++ discussion newsgroup is the wrong place to
have this discussion, as most C++ developers only have experience with
the broken C++ exception specification implementation, which isn't
going to give anyone much insight into the benefits of exception
specifications. It's like trying to have a discussion about garbage
collection, and people keep bringing up deficiencies specific to the
boehm garbage collector as criticism against GC in general.

That said, obviously we can get by without exception specifications. I
think they close a corner case in the language, help documentation,
and help give a clearer idea of what exceptions should be handled and
what ones shouldn't be (as long as there is the checked/unchecked
distinction) but it clearly isn't an essential feature, and when it is
present, people often screw up the use. However, you could say the
same thing about exceptions in general.

--

Karl Uppiano

unread,
Nov 28, 2008, 10:50:27 AM11/28/08
to

"Bart van Ingen Schenau" <ba...@ingen.ddns.info> wrote in message

news:1862298.H...@ingen.ddns.info...

No, but if the API were to include an exception specification in the
template from the outset, it would be part of the API "contract". Specific
exception types would be expected -- arguably better than return codes,
which are frequently ignored. The exception declaration would not require an
implementation to throw the exception, but it would tell the user that it
_can_ throw that exception, and to expect it. An implementation can throw a
more derived exception if it needs to provide additional information. It is
an engineering challenge for the template designer to declare the kinds of
exceptions that should be expected here -- but that is no more demanding
than selecting the right error return codes.

> As for turning client-specific exceptions into a generic
> creation_exception, I don't like throwing away information that my
> client might want to have, simply because I have an overly strict
> exception specification to meet.

That was my "work-around" in the event of a legacy requirement. New code
would throw the declared exceptions or more specialized subclasses thereof.
Bizarre exceptions coming out of left field would be a rarity if the API
designer declared exceptions having informative names and the proper
semantics.

> Additionally, how do you like adding useless try-catch blocks to keep
> the compiler happy, because you know that my_container<int> will never
> ever throw a creation_exception, but the compiler doesn't.

I agree, my_container<int> is a special case, since most non-primitive types
might reasonably throw creation_exceptions of one kind or another. If you
really, really don't want to include the code to handle an exception that
could never be thrown, and if the standards committee really, really agree
that you should not have to bother with it, then I think they could provide
a way to acknowledge the exception without actually handling it. I don't
know how far down that path they would want to travel for what (IMHO) is a
pathological situation.

Slightly off-topic: One feature that I like in Java exception handling is
the concept of checked and unchecked exceptions. If C++ had this concept,
your objection might be less severe. Java exceptions that derive from
"RuntimeException" are unchecked. You can declare them (or handle them) if
you want, but the compiler doesn't require it. RuntimeExceptions are usually
reserved for things that may get thrown from anywhere, such as null
pointers, array index out of bounds, invalid arguments, or system errors
such as out of memory, stack overflow, etc. These are exceptions that would
otherwise require every single method to declare -- or situations that the
application space might not be equipped to deal with, and should be thrown
all the way up to the default handler.

>> My work requires that I move freely and frequently between Java and
>> C++. That has influenced my C++ coding style. Having seen "exceptions
>> done right", I now use exceptions in C++ with far more regularity than
>> I used to.
>
> Before people start to misunderstand me, I am not opposed to using
> exceptions. In fact, I think they are a wonderful tool.
>
> It is the use of exception *specifications* that I have issue with.
> There are just too many unsolved fundamental issues left for me to use
> or advocate them.

I found them to be intrusive when I first started in Java, but I gradually
came to appreciate them. It tends to keep error/exception handling higher up
in my consciousness. I am less likely to miss exception scenarios when using
an API, and I am more likely to think about expressing exceptional
situations when I design an API.

> Some of those issues also exist in Java, and the typical way that I have
> seen them solved is to ignore the error (catch the exception without
> and kind of handling). Sometimes that might be the correct reaction,
> but if it happens to all exceptions that the base-class/interface
> version of the function does not mention in the exception
> specification, then it becomes suspicious.

Empty catch blocks in Java are considered very bad form. It is rarely the
correct reaction. If the app doesn't know what to do with the exception, it
then should let it fly. It should not eat it unless exception recovery is
truly a no-op (IME, it rarely is that).


--

Francis Glassborow

unread,
Nov 28, 2008, 3:47:28 PM11/28/08
to
Thomas Beckmann wrote:
> In summary,
> if there is a GC you have no dtors, and
> if you have dtors you need no finallies...
>
>

And yet considerable effort has been and is going on to provide GC for
C++ :}

--
Note that robinton.demon.co.uk addresses are no longer valid.

Bart van Ingen Schenau

unread,
Nov 29, 2008, 2:31:26 PM11/29/08
to
Richard Corden wrote:

> Hi,
>
> Bart van Ingen Schenau wrote:
>>
>> Which would make the container unusable with types from third-party
>> libraries that don't have their exception hierarchy rooted in
>> std::exception,
>
> Yes. In the same way that 3rd party types that are not copyable
> cannot
> be used in std::vector today. It is just a different constraint on
> that
> vector. However, why not have 2 vectors, one that's checked when you
> know exactly what your element type throws, and one where you don't.

But I DO know exactly what my element type throws. It is just not a type
that is derived from std::exception.

>
>> and it does not buy you anything in terms of statically checking
>> exception specifications. The empty specificantion is just replaced
>> with a 'throw(std::exception)' and you are still no wiser if all
>> possible exceptions are actually handled.
>
> Static checking would be able to identify a copy constructor that has
> no exception specification, or one that explicitly states that it
> throws
> say "int". It would also protect you in the cases where you
> accidentally called a member function of the vector from a function
> with a "throw()" spec.

I think you misunderstood my comment.
Yes, static checking can catch those errors, if you use specifications
that are narrowed down enough.

In terms of catching these kinds of errors, I don't see much difference
in error detection between knowing that anything at all can be thrown
or knowing that anything derived from std::exception can be thrown.

>
> If a 3rd party library is being used in a project, then the client of
> that code *should* know what can be thrown.

Most of the time, the programmer using the library knows exactly what
can be thrown. For useful static checking, the compiler must have the
same information.
With the current tools, if an object from library A is passed to a
template from library B, then part of the information gets lost for the
compiler.

>
> There is always the choice to use the current std::vector or they
> might
> use a checked vector. Such a new vector type could use variadic
> templates to allow the specification of the types that the element
> type actually throws!
>
> std::spec_vector<A, int, char /* throws int and char */> v;
>
>
> The real problem today is that there is no checking at all. In
> current C++ if you use exception specifications and get it wrong, then
> your
> program can simply die horribly. Without static checking - the only
> safe option is to avoid specifications completely.

I agree that currently exception specifications are worse than useless.
I just don't think that statically checked specifications are a viable
option with the current state of C++.
I am not willing to write reams of
try {
...
} catch(...)
{
/* Should never happen */
assert(0);
}
boilerplate code just to keep the static verification of exception
specifications happy.

For me to accept the possibility of statically checked exception
specifications, the following two points must be covered in the
proposal:
- A way to specify the specification 'I throw <these exceptions> plus
whatever might be thrown by the functions I call' (or some other
solution for the problem of specifying exceptions for templates without
unduly restricting the types that can be used as template argument)
- A way to specify for a set of functions that they won't throw
anything. This is needed to avoid the boilerplate above when
interfacing with a C API.

>
>
> Regards,
>
> Richard
>
Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://c-faq.com/
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Falk Tannhäuser

unread,
Nov 29, 2008, 3:23:15 PM11/29/08
to
Brendan schrieb:

> Containers are only compatible with types
> designed to be compatible with them, that goes without saying. The
> standard containers don't work with many types, including those
> without copy constructors, those without relational operators (you
> can't just stick a pointer in a map), etc.

Pointers *are* suitable as key types for maps and sets since these
containers use std::less rather than operator< for key comparisons.
The Standard requires for templates greater, less, greater_equal, and
less_equal, the specializations for any pointer type to yield a total
order, even if the built-in operators <, >, <=, >= do not.

Falk

Joshua...@gmail.com

unread,
Nov 30, 2008, 3:55:40 AM11/30/08
to
Now, to add my own opinion to the mix, this just came to me while
rereading the posts in this thread.

Now, I'm sorry for this rehash, but I'm building up to a point in here
somewhere.

As I view exceptions, they are a direct parallel to error return
codes. They both have roughly the same expressive power. However, they
differ in implementation speed and in ease of use.

Return codes are opt-in. You have to explicitly and manually check for
error codes. The compiler cannot help you here. (At least not without
some language extensions like annotations saying "@returns_error_code"
allowing the compiler to differentiate between ignorable returns, like
std::map::insert, and actual error return codes.)

Exceptions are opt-out, at compile time or runtime, depending on the
language and flavor, e.g. checked vs unchecked exceptions. They are
not like error return codes. If you forget to check for them, either
your app will fail to compile or it'll fail quite noticably at
runtime.

Exceptions as commonly used also allowing separating error handling
code and normal code, one of my favorite things about them. Separation
of separate concerns is almost always a good idea.

Now, static checked exceptions in Java kind of go against this. They
require all helper functions to know about every single kind of
exception that can propagate. This partially defeats the utility of
exceptions, of being able to separate the error handling code from the
normal code. In Java, all of the helper functions have to know about
all possible propagatable exceptions, whereas in C++, it's like all
functions are marked as "throws Exception", the helper functions do
not have to know anything about error handling.

Now, I understand and really like the idea of statically checked
exceptions. However, for large projects, this requires a lot of
intrusive work, marking all throws specifications correctly for all
functions.

I will first note that most functions are not external APIs. Most
functions are helper functions, and they don't care about the
particular types of exceptions that might be thrown through them. What
you really want to do for most functions is say "I don't care what
this can throw. It's just some small helper function. Other code
creates the errors, and other code lower in the stack will handle the
errors."

What you want is something like "throws Exception" in Java, but the
problem with "throws Exception" is that all information on the various
types of exceptions which can be thrown is lost.

What if you could specify a function as "propagates_all"? When you
compile a "propagate_all" function, the compiler will determine all
possible (checked) exceptions which can be thrown, and will add this
specification to the compiled function object code. Later, other code
which has a throws specification can be matched by checking all called
functions statically to make sure no unspecified (checked) exceptions
escape.

Moreover, this "propagates_all" could be the default, aka if you do
not have a throws specification on a function, it could default to
"propagates_all". (Or it could not. I haven't given this much
thought.)

I understand that this may be impractical because all current C++
compilers hijack existing object formats, and this would require a new
kind of object format to store the exception specifications. (Might
also cause problems for shared libraries, dlopen and such.) I also
understand that this would be a breaking change to C++, so it also
probably won't happen for that reason. Those aside, anyone like my
idea?

--

zai...@zaimoni.com

unread,
Nov 30, 2008, 6:30:19 PM11/30/08
to
On Nov 30, 2:55 am, JoshuaMaur...@gmail.com wrote:
> Now, to add my own opinion to the mix, this just came to me while
> rereading the posts in this thread.

> What if you could specify a function as "propagates_all"? When you


> compile a "propagate_all" function, the compiler will determine all
> possible (checked) exceptions which can be thrown, and will add this
> specification to the compiled function object code. Later, other code
> which has a throws specification can be matched by checking all called
> functions statically to make sure no unspecified (checked) exceptions
> escape.

This is necessary simplify to avoid pessimization with exception
specifications.

> Moreover, this "propagates_all" could be the default, aka if you do
> not have a throws specification on a function, it could default to
> "propagates_all".

Exactly. Making this the default, combined with giving practically
all default-defined operators throw() exception specifications, will
make this viable (given an appropriate object format).

> ... I also


> understand that this would be a breaking change to C++, so it also
> probably won't happen for that reason.

I don't see why this is a breaking change in C++ at all: no existing
source code should break. (It'll break all *implementations*, but
that is another story.)

Bart van Ingen Schenau

unread,
Nov 30, 2008, 6:30:51 PM11/30/08
to
Karl Uppiano wrote:

> "Bart van Ingen Schenau" <ba...@ingen.ddns.info> wrote in message

> news:1862298.H...@ingen.ddns.info...


>>
>> The big problem here is that templates (especially template
>> *libraries*) are NOT developed together with the client code.
>> And I don't consider interoperability with other libraries to be a
>> legacy issue, especially if you start requiring clients of your
>> template to throw specific exceptions.
>
> No, but if the API were to include an exception specification in the
> template from the outset, it would be part of the API "contract".
> Specific exception types would be expected -- arguably better than
> return codes, which are frequently ignored. The exception declaration
> would not require an implementation to throw the exception, but it
> would tell the user that it _can_ throw that exception, and to expect
> it. An implementation can throw a more derived exception if it needs
> to provide additional information. It is an engineering challenge for
> the template designer to declare the kinds of exceptions that should
> be expected here -- but that is no more demanding than selecting the
> right error return codes.

Now think about this scenario:
- Statically checked exceptions are realised
- Boost library requires client code to throw exceptions derived from
boost::exception.
- ACE library requires client code to throw exceptions derived from
ACE_Exception.
- The term 'client code' above refers to actual template arguments and
derived classes.

* I want to develop a new library that can be used with both Boost and
ACE, or alternatively
* I want to develop an application that uses both Boost and ACE.
What kind of exceptions should I be throwing from my classes/functions?
What if, in the library case, I want to support a third library that has
yet another base-class for its exceptions.

I can't use boost::exception-derived exceptions in one place and
ACE_Exception-derived ones in another, because a single class/function
could (potentially) be a client to both Boost and ACE.

>
>> As for turning client-specific exceptions into a generic
>> creation_exception, I don't like throwing away information that my
>> client might want to have, simply because I have an overly strict
>> exception specification to meet.
>
> That was my "work-around" in the event of a legacy requirement. New
> code would throw the declared exceptions or more specialized
> subclasses thereof. Bizarre exceptions coming out of left field would
> be a rarity if the API designer declared exceptions having informative
> names and the proper semantics.

See above how these 'bizarre' exceptions are far from a rarity. Or are
you suggesting that the C++ standard should specify all possible
classes that could be thrown?

Note that this problem does not occur in Java, because there it is
impossible (to my knowledge) that code from library A gets to call code
from library B directly without the designer/implementor/maintainer of
library A knowing about it.
In C++, templates completely change this equation.

Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://c-faq.com/
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Joshua...@gmail.com

unread,
Dec 1, 2008, 2:04:34 PM12/1/08
to
On Nov 30, 3:30 pm, Bart van Ingen Schenau <b...@ingen.ddns.info>
wrote:

> Karl Uppiano wrote:
> > That was my "work-around" in the event of a legacy requirement. New
> > code would throw the declared exceptions or more specialized
> > subclasses thereof. Bizarre exceptions coming out of left field would
> > be a rarity if the API designer declared exceptions having informative
> > names and the proper semantics.
>
> See above how these 'bizarre' exceptions are far from a rarity. Or are
> you suggesting that the C++ standard should specify all possible
> classes that could be thrown?
>
> Note that this problem does not occur in Java, because there it is
> impossible (to my knowledge) that code from library A gets to call code
> from library B directly without the designer/implementor/maintainer of
> library A knowing about it.
> In C++, templates completely change this equation.

First, I don't know for sure what you mean. Guessing what you mean, I
think you're wrong.

When a person writes a container like std::vector, he is going to be
calling the default constructor, the copy constructor, the destructor,
etc., of the types used to instantiate the template. When a person
writes an interface by specifying a base class with virtual functions
that the client should derive from, a callback interface perhaps, the
library code is still calling client code.

C++ templates are compile-time polymorphism, whereas virtual functions
are runtime polymorphism.

Java has virtual functions, so a Java library can call arbitrary code
which the designer of the library does not know about.

The distinction is that templates are more of a macro text
substitution, whereas virtual functions require a inheritance
relationship, but for the purposes of this discussion, I don't think
that matters. What matters is that in C++, the text-like macro
substitution of templates, and the calling of virtual functions, do
not statically enforce exception specifications like Java does when it
compiles function calls.

Also, I think it comes up less often in Java because Java focuses on
passing arguments and things by reference. The Java standard
containers never actually instantiate an object. (Moreover they can't
(easily) because of type erasure.) They only hold objects which have
already been instantiated, thus any operation on a Java standard
container does not call an operation on the generized type, unlike C++
containers which call the templated type's copy constructor, default
constructor, destructor, assignment operator, etc.

--

Gerhard Menzl

unread,
Dec 1, 2008, 3:09:04 PM12/1/08
to
Brendan wrote:

>> Richard Corden wrote:
>> Which would make the container unusable with types from third-party
>> libraries that don't have their exception hierarchy rooted in
>> std::exception,
>
> This is a non-argument. Containers are only compatible with types
> designed to be compatible with them, that goes without saying. The
> standard containers don't work with many types, including those
> without copy constructors, those without relational operators (you
> can't just stick a pointer in a map), etc. You only need an adapter if
> you want incompatible types to work together.

This is a flawed argument. Standard containers require copyability and
assignability because these operations are necessary to implement the
containers. But a standard container has no business whatsoever with
specific exceptions an item type may throw. All that is required is that
the container propagate the exception outward. Without exception
sepcifications, this is guaranteed by the language.

Think about what "an adapter [to make] incompatible types [...] work
together" would mean in the context of statically checked exception
specifications. Since it would be impossible for a standard container to
specify any exceptions other than standard exceptions, an adapter for a
container item would have to convert all user-specific exceptions to
stdandard exceptions, thereby preventing all non-standard information
from reaching higher-level code.

A major design goal of exceptions is the transparent handling of errors
across long calling distances without making intermediate code dependent
on the details. Statically checked exception specifications thwart this
purpose. It just doesn't scale, and it is incompatible with generic
programming.

--
Gerhard Menzl

Non-spammers may respond to my email address, which is composed of my
full name, separated by a dot, followed by at, followed by "fwz",
followed by a dot, followed by "aero".

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Gerhard Menzl

unread,
Dec 1, 2008, 3:08:42 PM12/1/08
to
Thomas Beckmann wrote:

Once again, this doesn't follow. You can plug the Boehm collector into
C++ and yet have destructors. What you cannot have is deterministic
destruction for garbage collected *objects*, since, by design, garbage
collection is non-deterministic from the perspective of the collector's
user. However, the presence of a garbage collector does not mean all
objects have to be garbage collected. This is only the case with Java,
the designers of which decided to do away with automatic objects. In
principle, there is no technical reasaon against garbage-collected and
automatic objects existing side-by-side.

--
Gerhard Menzl

Non-spammers may respond to my email address, which is composed of my
full name, separated by a dot, followed by at, followed by "fwz",
followed by a dot, followed by "aero".

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Thomas Beckmann

unread,
Dec 1, 2008, 5:08:11 PM12/1/08
to
> Once again, this doesn't follow. You can plug the Boehm collector into C++

> and yet have destructors. What you cannot have is deterministic
> destruction for garbage collected *objects*, since, by design, garbage
> collection is non-deterministic from the perspective of the collector's
> user. However, the presence of a garbage collector does not mean all
> objects have to be garbage collected. This is only the case with Java, the

> designers of which decided to do away with automatic objects. In
> principle, there is no technical reasaon against garbage-collected and
> automatic objects existing side-by-side.

Of course it is technically possible to create a GC and let it manage
memory. There is nothing to prevent you. Admitted, I base my statement on
the fact that a GC in a C++ software system is not a commonly used idiom.
The common case is to use deterministic destruction an dtors.

Notice, also it is well possible to use manual memory management in Java
code. Some people even tought operating systems classes in Java. Anyways, I
claim the presence of a GC in its current widely used form implies some form

of manual resource management for closing files and such. Same would be true

for letting a simple Boehm GC manage a file object in C++.

Anyways, this got way beyond my intention to give reasoning why there is no
try-finally build into the C++ language. Also, I certainly agree GCs make
life easier for business objects consisting of some memory with some data in

it. Dtors are better when a type focusses on resource management, i.e. RAII.

Here, we could add C#'s using statements to the soup...

To those who are interested in the topic of GCs there is an interesting
PodCast available at Software Engineering Radio which I found quite
inspiring since it highlight some technological aspects and limitations:
http://www.se-radio.net/podcast/2007-09/episode-68-dan-grossman-garbage-coll
ection-and-transactional-memory

--

Karl Uppiano

unread,
Dec 2, 2008, 10:33:19 AM12/2/08
to

"Bart van Ingen Schenau" <ba...@ingen.ddns.info> wrote in message

news:1779591.n...@ingen.ddns.info...

If I were writing templates, I would declare exceptions that derive from my
own exception hierarchy (could be Boost, ACE, or other, depending on who I
was), and are relevant to the semantics of _my_ problem space. If the client

class throws something else, the template would be responsible for
translating it into one of my exception types. My exception might support
_nesting_ the original cause for those who are interested. The fact that C++

allows people to throw _anything_ makes this more difficult.

All engineering is a compromise, and it all boils down to whether the good
outweighs the bad in a particular application or instance. You might elect
not to use the static checked exceptions in a given scenario. That doesn't
seem to be an argument for making it unavailable for the rest of us, whether

we could use it or not.

>>> As for turning client-specific exceptions into a generic
>>> creation_exception, I don't like throwing away information that my
>>> client might want to have, simply because I have an overly strict
>>> exception specification to meet.
>>
>> That was my "work-around" in the event of a legacy requirement. New
>> code would throw the declared exceptions or more specialized
>> subclasses thereof. Bizarre exceptions coming out of left field would
>> be a rarity if the API designer declared exceptions having informative
>> names and the proper semantics.
>
> See above how these 'bizarre' exceptions are far from a rarity. Or are
> you suggesting that the C++ standard should specify all possible
> classes that could be thrown?

I am suggesting that an API be able to declare exceptions that selected
methods are likely to throw, which it considers should be checked by the
compiler. I would further suggest that any exceptions not declared by the
API would be un-checked. So I could decide, inside my API, if I wanted to
handle third party exceptions, and translate them into one of my declared
exceptions, or just let them fly (assuming they are themselves un-checked
exceptions). If the third party exception is checked, then I would be
obliged to declare them too, or catch and translate. A robust,
general-purpose library would probably have to choose the latter.

> Note that this problem does not occur in Java, because there it is
> impossible (to my knowledge) that code from library A gets to call code
> from library B directly without the designer/implementor/maintainer of
> library A knowing about it.
> In C++, templates completely change this equation.

I am not sure what you mean here. There are differences between C++
templates and Java generics, but I think in this discussion, those
differences are not the issue. The entire Java API consists of libraries of
which the designer/implementer/maintainers have no idea how they are used.
In some cases, the API throws exceptions that they declare will be thrown
(and they provide the exception classes), that the client must catch. In
other cases, the client must implement interfaces that declare exceptions
which the client code must throw if an error occurs (and the interface
designer provides the exception classes). This has been going on for over
ten years, with relatively few problems that I am aware of. There are Java
Usenet discussions about the pros and cons (similar to this one), but as far

as I know there have been few if any insurmountable problems.


--

Gerhard Menzl

unread,
Dec 3, 2008, 11:22:19 AM12/3/08
to
Karl Uppiano wrote:

> If I were writing templates, I would declare exceptions that derive
> from my own exception hierarchy (could be Boost, ACE, or other,
> depending on who I was), and are relevant to the semantics of _my_
> problem space. If the client class throws something else, the template
> would be responsible for translating it into one of my exception
> types. My exception might support _nesting_ the original cause for
> those who are interested. The fact that C++ allows people to throw
> _anything_ makes this more difficult.

If you were writing templates, you would soon discover the true meaning
of the term "generic".

Suppose you were to write a standard-style container, i.e. a container
with copy semantics that is able to hold any type. Let's just look at a
simplified implementation of insert:

template <typename T> class my_container
{
//...

iterator insert(iterator pos, T const& item) throw (my_exception)
{
iterator new_pos = make_room(1);

try
{
*new_pos = item;
}
catch(...) // T might throw anything
{
// what goes here?
}

return new_pos;
}

//...
};

How could generic code possibly translate an exception that is specific
to T's problem domain into a generic format, and even if it could, how
could it avoid losing information? There's T-dom code on top which
understands and handles T-dom exceptions, and T-dom code at the bottom
which generates T-dom exceptions. You suggest that T-dom abandons its
specific exceptions although they make perfect sense, just because the
generic container is used in between. I don't see any sense in that.

--
Gerhard Menzl

Non-spammers may respond to my email address, which is composed of my
full name, separated by a dot, followed by at, followed by "fwz",
followed by a dot, followed by "aero".

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Karl Uppiano

unread,
Dec 3, 2008, 6:55:48 PM12/3/08
to

"Gerhard Menzl" <clcppm...@this.is.invalid> wrote in message
news:gh5l5r$rki$1...@news.datemas.de...

> Karl Uppiano wrote:
>
>> If I were writing templates, I would declare exceptions that derive
>> from my own exception hierarchy (could be Boost, ACE, or other,
>> depending on who I was), and are relevant to the semantics of _my_
>> problem space. If the client class throws something else, the template
>> would be responsible for translating it into one of my exception
>> types. My exception might support _nesting_ the original cause for
>> those who are interested. The fact that C++ allows people to throw
>> _anything_ makes this more difficult.
>
> If you were writing templates, you would soon discover the true meaning of
> the term "generic".

What makes you think that I don't?

> Suppose you were to write a standard-style container, i.e. a container
> with copy semantics that is able to hold any type. Let's just look at a
> simplified implementation of insert:
>
> template <typename T> class my_container
> {
> //...
>
> iterator insert(iterator pos, T const& item) throw (my_exception)
> {
> iterator new_pos = make_room(1);
>
> try
> {
> *new_pos = item;
> }
> catch(...) // T might throw anything
> {
> // what goes here?
> }
>
> return new_pos;
> }
>
> //...
> };

In my earlier post, I answered the question "what goes here" by saying that
C++ makes this task harder because T might throw anything. I am aware of
that problem -- and it is a huge problem. I personally think catch(...) is
evil, but unfortunately unavoidable for completely unconstrained generic
templates because of the way C++ evolved.

> How could generic code possibly translate an exception that is specific to
> T's problem domain into a generic format, and even if it could, how could
> it avoid losing information? There's T-dom code on top which understands
> and handles T-dom exceptions, and T-dom code at the bottom which generates
> T-dom exceptions. You suggest that T-dom abandons its specific exceptions
> although they make perfect sense, just because the generic container is
> used in between. I don't see any sense in that.

It depends on what the template is used for. If I wish to be transparent to
the T-domain, then I probably would not attempt to translate. If the
template API is the dominant domain, I would translate, and nest any
exceptions thrown by T so information is not lost (subject to catch(...)
evilness). Sometimes life sucks. It would be a nice compromise if I could
allow T's exceptions to pass unchecked, and declare my own as checked. I
don't think statically checked exception semantics work that way today.

In an earlier post, I also mentioned that T might throw a checked exception
that my template method doesn't declare. That presents a problem for classes
that are not aware of my template, but in many programming situations,
classes and templates are developed together, and it merely involves
agreement on the API, where statically checked exceptions could be
enormously helpful.

This thread is about how to address today's problems with statically checked
exceptions, so I look forward to the day when some of these problems are
mitigated. As a somewhat unsatisfying work-around, most compilers allow
specific warnings to be suppressed, for when new language features are more
strict than the old features.


--

Gerhard Menzl

unread,
Dec 4, 2008, 2:02:16 PM12/4/08
to
Karl Uppiano wrote:

> "Gerhard Menzl" <clcppm...@this.is.invalid> wrote


>> If you were writing templates, you would soon discover the true
>> meaning of the term "generic".
>
> What makes you think that I don't?

Your own use of the subjunctive ("If I were writing templates"), your
comparisons to Java, which has a much more limiting concept of
genericity and was originally conceived without any support for
generics, and your characterization of (largely) unconstrained
genericity as a weakness, which most C++ programmers regard as a strength.

> In my earlier post, I answered the question "what goes here" by saying
> that C++ makes this task harder because T might throw anything. I am
> aware of that problem -- and it is a huge problem. I personally think
> catch(...) is evil, but unfortunately unavoidable for completely
> unconstrained generic templates because of the way C++ evolved.

There, that's what I was referring to above. I agree that the value of
catch(...) is limited. Basically, logging that some unknown error
occurred is all that it allows you to do (aside from cleanup, which
should be taken care of by RAII objects anyway). The irony is that the
necessity to use catch(...) in generic code is only introduced when you
add non-empty exception specifications. Without them, the unknown
exception just passes through transparently, up to higher-level code,
where it *is* known. This is a significant reduction of coupling. Or
rather: requiring intermediate code to honour all exception types
*increases* coupling.

> It depends on what the template is used for. If I wish to be
> transparent to the T-domain, then I probably would not attempt to
> translate. If the template API is the dominant domain, I would
> translate, and nest any exceptions thrown by T so information is not
> lost (subject to catch(...) evilness). Sometimes life sucks. It would
> be a nice compromise if I could allow T's exceptions to pass
> unchecked, and declare my own as checked. I don't think statically
> checked exception semantics work that way today.

If my reading of "the dominant domain" as domain-specific is correct,
you have a contradiction in terms. By definition, generic is the
opposite of specific. The idea is to avoid repeated coding of frequently
used concepts, such as containers or algorithms, without depending on
the more specific parts. Imposing the obligation to acknowledge specific
interfaces (read: exceptions) defeats this purpose.

> In an earlier post, I also mentioned that T might throw a checked
> exception that my template method doesn't declare. That presents a
> problem for classes that are not aware of my template, but in many
> programming situations, classes and templates are developed together,
> and it merely involves agreement on the API, where statically checked
> exceptions could be enormously helpful.

Of course, this problem is less likely to occur or doesn't arise at all
with templates that are more domain-specific and are meant to be
instantiated for a few well-known types. But that's beside the point.
The objection was: what about really generic code?

--
Gerhard Menzl

Non-spammers may respond to my email address, which is composed of my
full name, separated by a dot, followed by at, followed by "fwz",
followed by a dot, followed by "aero".

ThosRTanner

unread,
Dec 4, 2008, 2:03:25 PM12/4/08
to
On Nov 20, 9:37 pm, DeMarcus <demar...@hotmail.com> wrote:
> Hi,
>
> Recently I bought the book C++ Coding Standards by Sutter and
> Alexandrescu. The book is good but there's one thing that they comment
> in a way that doesn't feel right. I talk about item 75 in the book.
>
> Item 75 says: "Avoid exception specifications.".
>
> The authors have a lot of good arguments for not using exception
> specifications, but there's one thing they're missing; the
> specifications have a purpose, or at least should have. The authors
> neglect this fact with following argument: "People often suggest
> switching from dynamically checked exception specifications to
> statically checked ones, as provided in Java and other languages. In
> short, that just trades one set of problems for another; users of
> languages with statically checked exception specifications seem to
> equally often suggest switching to dynamically checked ones."
>
> I don't blame the authors, don't take me wrong, but to me it seems like
> the exception specifications need to be fixed when two of the most
> renowned C++ programmers recommend us to avoid them.

Exception specifications come up on this group from time to time, and
generally generate a lot of noise.

What I've found is that:
1) You cannot use exception specifications in an environment where it
is not acceptable for a program to stop running. This is because they
are run time checked, and so if some piece of code throws an
unexpected exception, the run-time terminates your program.
2) Someone always says that you cannot possibly compile time check the
exception specification. This is absolute tosh, the exception
specification is part of the function prototype (or whatever it is
correctly called), and to call the function, the protoype must be
available to the compiler. Hence the exception specification can be
checked
3) templates. If one viewed the template definition as providing an
interface specification that can be conformed to, this might be
considered as less of a cause of grief. something like

template <class A> wibble(A const &) throw(type);

is basically saying that wibble can only throw exceptions of type type
(or types derived from type). I don't see that as particularly non-
generic. If you don't care what wibble throws, don't put a throw spec
in.

static exception specifications don't loose you anything (except nasty
surprises at runtime), and they gain you a lot of rigour. But rigour
seems to be a bit of a dirty word.

--

Francis Glassborow

unread,
Dec 4, 2008, 2:03:55 PM12/4/08
to
Karl Uppiano wrote:

> This thread is about how to address today's problems with statically checked
> exceptions, so I look forward to the day when some of these problems are
> mitigated. As a somewhat unsatisfying work-around, most compilers allow
> specific warnings to be suppressed, for when new language features are more
> strict than the old features.
>
>

Unless you can come up with a workable way to deal with generic
containers (e.g. std::vector) the number of places where a third party
library could usefully use checked exceptions is minuscule. I guess that
I am in the majority in wanting to be able to have containers of objects
and handle exception generated by use of the members of the container.

const correctness is reasonably achievable (in C++, C has a problem
because it does not yet support overloading which is essential for
smooth support of const correctness). 'Exception correctness' is orders
of magnitude worse than the problems C has with const. Furthermore
statically checked exception specifications without the programmer
adding a complete exception specification to every function (and thereby
loosing the transparency of exceptions for error handling) is certainly
very hard to achieve in the context of separate compilation.

IIUC Java does not have a notion of separate compilation and so does not
have that problem. Nonetheless Java programmers tell me that checked
exception specs are at best a mixed blessing.

--
Note that robinton.demon.co.uk addresses are no longer valid.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Geert-Jan Giezeman

unread,
Dec 4, 2008, 2:01:32 PM12/4/08
to
Karl Uppiano wrote:
> It would be a nice compromise if I could
> allow T's exceptions to pass unchecked, and declare my own as checked. I
> don't think statically checked exception semantics work that way today.

> This thread is about how to address today's problems with statically checked


> exceptions, so I look forward to the day when some of these problems are
> mitigated.

I see that you would like to have checked and unchecked exceptions. In
the presence of unchecked exceptions, is there any chance of statically
checking that a function does not throw? This looks like a vital
condition for achieving various levels of exception safety.

Geert-Jan Giezeman

DeMarcus

unread,
Dec 4, 2008, 7:11:51 PM12/4/08
to
Gerhard Menzl wrote:
>
> Suppose you were to write a standard-style container, i.e. a container
> with copy semantics that is able to hold any type. Let's just look at a
> simplified implementation of insert:
>
> template <typename T> class my_container
> {
> //...
>
> iterator insert(iterator pos, T const& item) throw (my_exception)
> {
> iterator new_pos = make_room(1);
>
> try
> {
> *new_pos = item;
> }
> catch(...) // T might throw anything
> {
> // what goes here?
> }
>
> return new_pos;
> }
>
> //...
> };
>
> How could generic code possibly translate an exception that is specific
> to T's problem domain into a generic format, and even if it could, how
> could it avoid losing information? There's T-dom code on top which
> understands and handles T-dom exceptions, and T-dom code at the bottom
> which generates T-dom exceptions. You suggest that T-dom abandons its
> specific exceptions although they make perfect sense, just because the
> generic container is used in between. I don't see any sense in that.
>

I see templates as a programming assistant; the templates and
pre-processor help you do the tedious work that you do over and over
again just slightly different. If we would not have had the templates we
would have done copy and paste and tweaked the exceptions (if used) for
the new type used in the container.

I'm a programmer, still I have a lot to learn about compilers. But
please answer me why can't the pre-processor just take the exceptions
from the template and add the exceptions from type T into the exception
specification before compilation?


--

Karl Uppiano

unread,
Dec 4, 2008, 8:18:37 PM12/4/08
to
"Gerhard Menzl" <clcppm...@this.is.invalid> wrote in message
news:gh87f1$lr7$1...@news.datemas.de...

> Karl Uppiano wrote:
>
>> "Gerhard Menzl" <clcppm...@this.is.invalid> wrote
>>> If you were writing templates, you would soon discover the true
>>> meaning of the term "generic".
>>
>> What makes you think that I don't?
>
> Your own use of the subjunctive ("If I were writing templates"), your
> comparisons to Java, which has a much more limiting concept of
> genericity and was originally conceived without any support for
> generics, and your characterization of (largely) unconstrained
> genericity as a weakness, which most C++ programmers regard as a strength.

Sorry my phraseology was hypothetical. I did not mean to characterize
unconstrained genericity as a weakness. But not all code needs to be
unconstrained generic. Ultimately, practically all code is application
specific. It might be true that statically checked exceptions are not
compatible with completely unconstrained genericity, but I suspect that
there are elegant ways to mitigate or eliminate that. I haven't spent the
amount of mental energy necessary to figure out what that is. It might
require C++ language spec wonks a long time to do it (and I'm not one of
them).

>> In my earlier post, I answered the question "what goes here" by saying
>> that C++ makes this task harder because T might throw anything. I am
>> aware of that problem -- and it is a huge problem. I personally think
>> catch(...) is evil, but unfortunately unavoidable for completely
>> unconstrained generic templates because of the way C++ evolved.
>
> There, that's what I was referring to above. I agree that the value of
> catch(...) is limited. Basically, logging that some unknown error
> occurred is all that it allows you to do (aside from cleanup, which
> should be taken care of by RAII objects anyway). The irony is that the
> necessity to use catch(...) in generic code is only introduced when you
> add non-empty exception specifications. Without them, the unknown
> exception just passes through transparently, up to higher-level code,
> where it *is* known. This is a significant reduction of coupling. Or
> rather: requiring intermediate code to honour all exception types
> *increases* coupling.

As I said in an earlier post, all engineering is a compromise. There are
conflicting requirements. If coupling is your number one most important
feature, then everything else must be subservient. But there is also the
question of having the ability to fully specify your API in a language aware
way. I still argue that statically checked exceptions can be very useful in
many situations, and superior to enumerated return codes or "surprise"
exceptions that no one is really knows in advance how to handle. Please do
not think I am arguing that you must use statically checked exceptions if
they don't make sense in any given scenario. Whatever the C++ spec
ultimately says about them should be flexible enough to handle most
situations, or be turned off if necessary.

>> It depends on what the template is used for. If I wish to be
>> transparent to the T-domain, then I probably would not attempt to
>> translate. If the template API is the dominant domain, I would
>> translate, and nest any exceptions thrown by T so information is not
>> lost (subject to catch(...) evilness). Sometimes life sucks. It would
>> be a nice compromise if I could allow T's exceptions to pass
>> unchecked, and declare my own as checked. I don't think statically
>> checked exception semantics work that way today.
>
> If my reading of "the dominant domain" as domain-specific is correct,
> you have a contradiction in terms. By definition, generic is the
> opposite of specific. The idea is to avoid repeated coding of frequently
> used concepts, such as containers or algorithms, without depending on
> the more specific parts. Imposing the obligation to acknowledge specific
> interfaces (read: exceptions) defeats this purpose.

The template itself has an API, behaviors and other constraints. Adding
typed exceptions admittedly adds another constraint. I am not oblivious to
that. My argument is that knowing what exceptions to expect in a
language-aware way might be worth the trade-off in many instances,
especially if it can be disabled for the instances where it isn't worth it.

>> In an earlier post, I also mentioned that T might throw a checked
>> exception that my template method doesn't declare. That presents a
>> problem for classes that are not aware of my template, but in many
>> programming situations, classes and templates are developed together,
>> and it merely involves agreement on the API, where statically checked
>> exceptions could be enormously helpful.
>
> Of course, this problem is less likely to occur or doesn't arise at all
> with templates that are more domain-specific and are meant to be
> instantiated for a few well-known types. But that's beside the point.
> The objection was: what about really generic code?

I think I have already said that as it stands today, statically checked
exceptions can be a problem for really generic code, and I am hoping for
improvements in those areas.


--

Karl Uppiano

unread,
Dec 4, 2008, 8:18:35 PM12/4/08
to
"Geert-Jan Giezeman" <ge...@cs.uu.nl> wrote in message
news:gh83qo$2sh$1...@prometheus.cs.uu.nl...

> Karl Uppiano wrote:
>> It would be a nice compromise if I could
>> allow T's exceptions to pass unchecked, and declare my own as checked. I
>> don't think statically checked exception semantics work that way today.
>
>> This thread is about how to address today's problems with statically
>> checked
>> exceptions, so I look forward to the day when some of these problems are
>> mitigated.
>
> I see that you would like to have checked and unchecked exceptions. In
> the presence of unchecked exceptions, is there any chance of statically
> checking that a function does not throw? This looks like a vital
> condition for achieving various levels of exception safety.

I think if you declare that a method does not throw, you might have to
guarantee that it doesn't, I.e., by using catch(...), unless the methods you
call also don't throw.

Listen, I feel as if I am defending a bunch of things that do not at this
time even exist in the language. I think statically checked exceptions,
properly specified in C++ would be very useful. Are there disadvantages? Of
course. There's never a free lunch. Can people dream up instances where they
would be more trouble than they're worth? Certainly. But we have an example
of at least one language where statically checked exceptions seems to be
quite successful. It's true, some people don't like it. If we took a vote, I
think there would be more people who prefer it, but maybe not.

My personal experience is, I have spent many years programming in C, then
C++, and then Java. I have lived in each language for years at a time, and
written many different kinds of applications in each one. I have things to
like and things not to like in each one. I like statically checked
exceptions in Java, and I miss it in C++. It requires a different way of
thinking, and it took me a while to warm up to it. But once I finally got
it, I found it to be very powerful, and it helped me write more robust and
cleaner code.

Joshua...@gmail.com

unread,
Dec 5, 2008, 9:34:24 PM12/5/08
to
On Dec 4, 4:11 pm, DeMarcus <demar...@hotmail.com> wrote:
> I see templates as a programming assistant; the templates and
> pre-processor help you do the tedious work that you do over and over
> again just slightly different. If we would not have had the templates we
> would have done copy and paste and tweaked the exceptions (if used) for
> the new type used in the container.
>
> I'm a programmer, still I have a lot to learn about compilers. But
> please answer me why can't the pre-processor just take the exceptions
> from the template and add the exceptions from type T into the exception
> specification before compilation?

First, the obligatory correct: template instantiation happens during
compilation. It is not part of the preprocessor, nor does it happen
after the preprocessor and before compilation. One reason the standard
demands this to determine what the following means:
A < B > C;
Is this declaring a variable C of type A<B>, or is it (A<B) > C,
possibly calling user defined operators < and >.


Now, your idea that the template instantiation take the exception
types from the template argument to use for the throws specifications?
This has been addressed several times in this thread. Thomas Beckmann
suggested having a certain typedef-like-thingy, the name is by
convention or by standard hackery, which you declare in the type you
will use in your template argument type, and the template will add
this typedef-like-thingy to the throws specification of the functions.
However, this is not possible in current C++. My earlier suggestion
was that the compiler will implicitly create the minimal throws
specifications when it compiles a function, and I guess at link time
it ensures that all functions only throw what's in their throws
specifications, which is again not standard C++. What you, Thomas, and
I want is not possible in standard C++.


Note that Thomas Beckmann's solution is more plausible in terms of
current C++ implementations but probably not well like by C++
programmers; it breaks the separation of error handling and normal
code that we all love about exceptions. (It would require you to add
these typedef-like-thingies, where the status-quo and my solution
would not.)

I think the C++ programmer community might / could like my solution.
However, my solution would probably require a new kind of object file
format, so my solution is probably not happening. There's a lot of
inertia behind using a C compatible object file format, name mangling
and all. Such formats are used for a variety of languages, including C
and C++, and others like (maybe?) Fortran, COBOL, etc. Linkers and
dynamic loaders work for all of these languages because of this common
object file format, so C++ implementers and OS implementers would not
be happy with this change. (I don't know enough to comment on whether
a new kind of object file format is actually needed. A hijack of a
comments area might suffice, or maybe some other hackery where the
linker isn't required to check exception specifications. I don't
know.)

Gerhard Menzl

unread,
Dec 5, 2008, 9:34:32 PM12/5/08
to
Karl Uppiano wrote:

> As I said in an earlier post, all engineering is a compromise. There
> are conflicting requirements. If coupling is your number one most
> important feature, then everything else must be subservient. But there
> is also the question of having the ability to fully specify your API
> in a language aware way. I still argue that statically checked
> exceptions can be very useful in many situations, and superior to
> enumerated return codes or "surprise" exceptions that no one is really
> knows in advance how to handle. Please do not think I am arguing that
> you must use statically checked exceptions if they don't make sense in
> any given scenario. Whatever the C++ spec ultimately says about them
> should be flexible enough to handle most situations, or be turned off
> if necessary.

Coupling is not my "number one most important feature", it's a serious
software design issue that affects extensibility and maintainability. In
my experience, the majority of code written in the field suffers from
too much coupling.

The alternative to statically checked exceptions is neither "enumerated
return codes" nor "exceptions that no one is really knows in advance how
to handle". There is no discussion that an exception that is thrown
needs to be handled at some point. What I contest, and what exception
specifications require, is that all code that lies *between the point of
throw and the point of catch* needs to be aware of all exception types.
You seem to argue that the resulting increase in coupling is offset by
the advantages, but frankly, I don't see what they are.

> The template itself has an API, behaviors and other constraints.
> Adding typed exceptions admittedly adds another constraint. I am not
> oblivious to that.

Exception checking (which is what you probably mean by "typed
execptions") does not just add "another constraint" to a template, it
adds an unbounded set of constraints.

> I think I have already said that as it stands today, statically
> checked exceptions can be a problem for really generic code, and I am
> hoping for improvements in those areas.

Improvement in what sense?


--
Gerhard Menzl

Non-spammers may respond to my email address, which is composed of my
full name, separated by a dot, followed by at, followed by "fwz",
followed by a dot, followed by "aero".

Karl Uppiano

unread,
Dec 5, 2008, 9:34:23 PM12/5/08
to
"Francis Glassborow" <francis.g...@btinternet.com> wrote in message
news:QZadnTm6msSAIKrU...@bt.com...

> Karl Uppiano wrote:
>
>> This thread is about how to address today's problems with statically
>> checked
>> exceptions, so I look forward to the day when some of these problems are
>> mitigated. As a somewhat unsatisfying work-around, most compilers allow
>> specific warnings to be suppressed, for when new language features are
>> more
>> strict than the old features.
>>
>>
>
> Unless you can come up with a workable way to deal with generic
> containers (e.g. std::vector) the number of places where a third party
> library could usefully use checked exceptions is minuscule. I guess that
> I am in the majority in wanting to be able to have containers of objects
> and handle exception generated by use of the members of the container.

I probably won't be coming up with that solution. I was hoping the C++
standards committee would do that.

> const correctness is reasonably achievable (in C++, C has a problem
> because it does not yet support overloading which is essential for
> smooth support of const correctness). 'Exception correctness' is orders
> of magnitude worse than the problems C has with const. Furthermore
> statically checked exception specifications without the programmer
> adding a complete exception specification to every function (and thereby
> loosing the transparency of exceptions for error handling) is certainly
> very hard to achieve in the context of separate compilation.

I'll grant you, it is harder in C++ than in some other languages, especially
for legacy compatibility with things such as the std template library.
Perhaps it is impossible, but I would welcome a solution if it could address
most of the common use cases, and perhaps be disabled for the corner cases.

> IIUC Java does not have a notion of separate compilation and so does not
> have that problem. Nonetheless Java programmers tell me that checked
> exception specs are at best a mixed blessing.

I think it is a bit of an overstatement to say that checked exception specs
are _at best_ a mixed blessing. I have worked on very large projects with
many other Java developers and hang out on Java forums, and I have never
heard anyone consider them a major drawback to the language. There are
healthy debates about specific things that are harder/easier to do, having
them around. It takes some getting used to, but I now miss them whenever I
switch back to coding in C++. It must be a cultural thing. I'll shut up
about it now.

--

Gerhard Menzl

unread,
Dec 5, 2008, 9:34:31 PM12/5/08
to
DeMarcus wrote:

> I see templates as a programming assistant; the templates and
> pre-processor help you do the tedious work that you do over and over
> again just slightly different. If we would not have had the templates
> we would have done copy and paste and tweaked the exceptions (if used)
> for the new type used in the container.

Actually, the difference is huge. The preprocessor is a rather dumb text
replacing tool which is oblivious of the language proper. Templates are
part of the language and constitute a Turing-complete metaprogramming
language.

> I'm a programmer, still I have a lot to learn about compilers. But
> please answer me why can't the pre-processor just take the exceptions
> from the template and add the exceptions from type T into the
> exception specification before compilation?

The preprocessor is, as I said, oblivious of the grammar, performs its
work before template instantiation takes place, and could therefore not
do any such thing. The template instantiation engine within the compiler
probably could (I am not a compiler writer either), but this would
ultimately result in templates allowing exceptions of any type - which
is what we already have today.


--
Gerhard Menzl

Non-spammers may respond to my email address, which is composed of my
full name, separated by a dot, followed by at, followed by "fwz",
followed by a dot, followed by "aero".

Bart van Ingen Schenau

unread,
Dec 6, 2008, 3:59:57 PM12/6/08
to
Karl Uppiano wrote:

> Listen, I feel as if I am defending a bunch of things that do not at
> this time even exist in the language. I think statically checked
> exceptions, properly specified in C++ would be very useful. Are there
> disadvantages? Of course. There's never a free lunch. Can people dream
> up instances where they would be more trouble than they're worth?
> Certainly. But we have an example of at least one language where
> statically checked exceptions seems to be quite successful. It's true,
> some people don't like it. If we took a vote, I think there would be
> more people who prefer it, but maybe not.

I agree that, if properly specified, statically checked exception
specifications can be very useful.

The reason I am currently opposed to statically checked exception
specifications is that I have not seen a proper specification for their
use in C++. I am opposed because I fear that the feature might be
introduced with an improper specification.
And with an improper specification, statically checked exception
specifications would be worse than the status-quo of runtime checked
exception specification (if that is possible).

Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://c-faq.com/
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Daniel James

unread,
Dec 6, 2008, 3:59:43 PM12/6/08
to
In article
news:<e78c57fb-1a3e-49a4...@h20g2000yqn.googlegroups.com

>, ThosRTanner wrote:
> What I've found is that:
> 1) You cannot use exception specifications in an environment where
> it is not acceptable for a program to stop running. This is because
> they are run time checked, and so if some piece of code throws an
> unexpected exception, the run-time terminates your program.

That argument is often raised, and the usual response is that if you
have an unexpected exception at all it probably isn't safe to allow the
program to continue. I would agree with you that if there is an
unexpected exception the program should at least have the opportunity
to shut itself down safely before it terminates.

I have always been very much against C++'s runtime checking of
exception specifications -- that seems to me to violate the rule that
you shouldn't have to pay for what you don't use. If a programmer wants
to check that only a specific exception is thrown he can always write
something like:

try
{
foo( bar ); // can throw baz
}
catch( const baz& e )
{
throw;
}
catch( ... )
{
throw unexpected;
}

As we can do this manually where it is wanted, we should NOT have to
suffer the cost of its being done automatically where it isn't.

The good thing about the current state of affairs is that it means that
almost nobody uses exception specs, so we can deprecate them without
breaking much code.

> 2) Someone always says that you cannot possibly compile time
> check the exception specification. This is absolute tosh, the
> exception specification is part of the function prototype (or
> whatever it is correctly called), and to call the function,
> the protoype must be available to the compiler. Hence the
> exception specification can be checked

I'm sure it's possible to write lint-like tools to check exception
safety of programs by full sourcecode analysis without placing any
exception specifications in the code at all. One only has to match up
all the throws and catches ...

Where sourcecode is not available for some modules (e.g. a 3rd-party
library) it would be sufficient to document the exceptions throwable by
the public interface. There is therefore no need to provide exception
specifications in the body of the source.

Templates might still be problematic, but in many cases such a tool
would be able to deduce the exceptions throwable by each instantiation
of a template at the point of instantiation.

> ... something like


>
> template <class A> wibble(A const &) throw(type);
>
> is basically saying that wibble can only throw exceptions of type
> type (or types derived from type). I don't see that as particularly

> non-generic. If you don't care what wibble throws, don't put a throw
> spec in.

What if wibble can throw more than one type?

--
Daniel James | djng
Sonadata Limited | at sonadata
UK | dot co dot uk

Bart van Ingen Schenau

unread,
Dec 6, 2008, 4:00:25 PM12/6/08
to
DeMarcus wrote:

> I see templates as a programming assistant; the templates and
> pre-processor help you do the tedious work that you do over and over
> again just slightly different. If we would not have had the templates
> we would have done copy and paste and tweaked the exceptions (if used)
> for the new type used in the container.

Please note that the pre-processor and templates are two completely
different things.
The pre-processor only interprets lines that start with a # mark and
does text substitution using #define-d macros on the program text.
Templates on the other hand, provide the compiler with a blueprint on
how to create new classes or functions.

For simple uses, templates and macros may feel similar, but the
underlying technology is completely different and with more complex
usage scenarios, they move further and further apart.

>
> I'm a programmer, still I have a lot to learn about compilers. But
> please answer me why can't the pre-processor just take the exceptions
> from the template and add the exceptions from type T into the
> exception specification before compilation?
>

The reason is simple: the pre-processor does not understand C++ syntax.
And also, when the source text of the template is being processed, it is
generally not known what type T will be, so you can not amend the
exception specifications at that time.

But otherwise I agree with you. There should be a way to specify that a
template can throw whatever T throws (in addition to what the template
itself throws).

Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://c-faq.com/
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Karl Uppiano

unread,
Dec 6, 2008, 4:01:07 PM12/6/08
to

"Gerhard Menzl" <clcppm...@this.is.invalid> wrote in message

news:ghaqap$q5b$1...@news.datemas.de...


> Karl Uppiano wrote:
>
>> As I said in an earlier post, all engineering is a compromise. There
>> are conflicting requirements. If coupling is your number one most
>> important feature, then everything else must be subservient. But there
>> is also the question of having the ability to fully specify your API
>> in a language aware way. I still argue that statically checked
>> exceptions can be very useful in many situations, and superior to
>> enumerated return codes or "surprise" exceptions that no one is really
>> knows in advance how to handle. Please do not think I am arguing that
>> you must use statically checked exceptions if they don't make sense in
>> any given scenario. Whatever the C++ spec ultimately says about them
>> should be flexible enough to handle most situations, or be turned off
>> if necessary.
>
> Coupling is not my "number one most important feature", it's a serious
> software design issue that affects extensibility and maintainability. In
> my experience, the majority of code written in the field suffers from
> too much coupling.

That may be, but it is not the only software design issue we have to
consider.

> The alternative to statically checked exceptions is neither "enumerated
> return codes" nor "exceptions that no one is really knows in advance how
> to handle". There is no discussion that an exception that is thrown
> needs to be handled at some point. What I contest, and what exception
> specifications require, is that all code that lies *between the point of
> throw and the point of catch* needs to be aware of all exception types.
> You seem to argue that the resulting increase in coupling is offset by
> the advantages, but frankly, I don't see what they are.

Not all exception types. Other languages that have used statically checked
exceptions successfully mix checked and unchecked exceptions. They (and I)
realize that it is not practical to declare every type of common exception
(e.g., stack overflow, out of memory, invalid pointer, array index out of
range, etc. are unchecked in Java). C++ lacks a standard set of exception
classes, which along with catch(...), is going to make statically typed
exceptions much more challenging.

>> The template itself has an API, behaviors and other constraints.
>> Adding typed exceptions admittedly adds another constraint. I am not
>> oblivious to that.
>
> Exception checking (which is what you probably mean by "typed
> execptions") does not just add "another constraint" to a template, it
> adds an unbounded set of constraints.

I think that depends on how statically checked exceptions are ultimately
implemented. You would have to prove to me that the set is unbounded, and
that there was no way to solve that. As I have said repeatedly, there should
be ways to work around it. In Java, you can throw an exception derived from
RuntimeException and you don't have to declare it. The compiler won't check
it, and at runtime, it will just go sailing right past anyone who doesn't
otherwise know it's coming. It isn't considered a best practice to use this
design pattern without careful thought, but the option exists in Java. This
particular solution is currently unavailable in C++ because the language
lacks a standard set of exception classes, and C++ is class-agnostic. That
is not a criticism or a recommendation, I am just stating the facts.

>> I think I have already said that as it stands today, statically
>> checked exceptions can be a problem for really generic code, and I am
>> hoping for improvements in those areas.
>
> Improvement in what sense?

Ways to address your objections while adding the ability to declare
exceptions as a language-aware part of an API. Perhaps similar to (or better
than) the things I mentioned above.


--

blargg

unread,
Dec 7, 2008, 6:30:43 AM12/7/08
to
I just don't see how exception specifications will ever be usable. The
fundamental problem: a function's exception specification depends on all
functions it calls, so any expansion of the called functions' exception
specifications requires a corresponding expansion in the function's
exception specification (or some conversion scheme). A central point of
exceptions is that most code can be free of reference to any specific
exception types; it just needs to behave properly in the presence of a
thrown exception through it. Exception specifications eliminate this, in
return giving the benefit of knowing every exception a function might
throw. I contend that in almost all cases, this is not even important,
and
even when it is, not worth the cost.

When I visualize the structure formed by exception specifications, it
looks almost like an inverted set of overloaded functions, where the
top-level catch handler(s) are the argument types the set of overloads
can
accept, and where all called functions must propagate "declarations" of
subsets of these overloads in their exception specifications, right down
to the lowest-level functions. This way, when a function throws an
exception, the set of "overloads" is examined to find if any can handle
that "argument" type. You want the compiler to diagnose any low-level
function which "passes" an argument type not handled by the top-level
"functions", therefore everything between that function and the
top-level
must recite the list of "argument" types accepted higher-up.

peter koch larsen

unread,
Dec 7, 2008, 10:11:55 PM12/7/08
to
On 7 Dec., 12:30, blargg....@gishpuppy.com (blargg) wrote:
> I just don't see how exception specifications will ever be usable. The
> fundamental problem: a function's exception specification depends on all
> functions it calls, so any expansion of the called functions' exception
> specifications requires a corresponding expansion in the function's
> exception specification (or some conversion scheme). A central point of
> exceptions is that most code can be free of reference to any specific
> exception types; it just needs to behave properly in the presence of a
> thrown exception through it. Exception specifications eliminate this, in
> return giving the benefit of knowing every exception a function might
> throw. I contend that in almost all cases, this is not even important,
> and
> even when it is, not worth the cost.
>
I agree 100%. In the general case, knowing what exceptions a function
might throw are not important, and form maintenance it could quite
easily become a nightmare with changes rippling through major parts of
the code.
One important exception to this rule is the empty exception
specification: These are often useful. For performance reasons it
could also be nice if you could "change the semantics", making the no
throw a promise causing undefined 8or unspecified) behaviour whenever
there was an actual in such a function.

Peter

blargg

unread,
Dec 8, 2008, 5:57:30 PM12/8/08
to
Eugene Gershnik wrote:
> On Nov 26, 10:55 am, "Nevin :-] Liber" <ne...@eviloverlord.com> wrote:
> > In article
> > <a7a665ad-87da-4319-9fd6-1e1c7fcbd...@v5g2000prm.googlegroups.com>,
> > EugeneGershnik<gersh...@gmail.com> wrote:
> >
> > > where emitted_by is a compile-time expression giving a typelist of
> > > types that an expression can throw.
> >
> > Why is this typelist any better in practice than not having exception
> > specifications? I just don't see people writing a TMP to make sure that
> > they have handled every possible exception.
>
> This is a very common misunderstanding. The purpose is emphatically
> *not* to make sure you handle every possible exception. It is to
> actually allow you to handle *some* exceptions.
> Consider this simple line of code
>
> int i = foo(42);
>
> Suppose you wanted to handle some recoverable errors that could be
> reported by foo.
[...]
> So how do you do that today? You go and read foo's documentation
> (which somebody had to write in the first place). You trust that it is
> accurate and is not going to change and wrap the call to foo is try/
> catch block to handle errors you want to handle.
>
> This is all completely manual and compiler will never help you there.
> This immediately produces all the disadvantages of things not enforced
> by a compiler. Even assuming docs exist and are accurate, if the foo's
> author changes its implementation in version 2 compiler will not alert
> you about new possible "rare but not completely unexpected" error that
> you might want to handle. It will not alert the author himself that
> the docs might need to be changed or some exceptions translated
> internally in order to conform to the published doc. Etc. etc.
>
> What compile-time exception specifications give you is an ability to
> have the compiler check the same things that you would have to put in
> the docs and verify manually *anyway*.
[...]

What about foo's implementation changing in other ways that could be
incompatible with some code out there? Why should changes in what
exceptions are thrown get special treatment by a compiler? It's not simply
a question of whether exception specifications are sometimes useful; it's
a question of whether the cost of adding exception specifications to every
function (and the ripple-effect updates when a low-level function's
exception specification is widened and all calling functions'
specifications must also widen) is worth the benefit of occasionally being
able to know exactly what is thrown.

Joshua...@gmail.com

unread,
Dec 9, 2008, 9:48:51 PM12/9/08
to
On Dec 8, 2:57 pm, blargg....@gishpuppy.com (blargg) wrote:

> Eugene Gershnik wrote:
> > What compile-time exception specifications give you is an ability to
> > have the compiler check the same things that you would have to put
> > in
> > the docs and verify manually *anyway*.
>
> [...]
>
> What about foo's implementation changing in other ways that could be
> incompatible with some code out there? Why should changes in what
> exceptions are thrown get special treatment by a compiler?

For the same reason the other parts of the function prototype get
"special treatment" by the compiler. The compiler will check that the
argument types are correct, that the cv qualifiers are consistent,
that the return code is correct, etc.


> It's not simply
> a question of whether exception specifications are sometimes useful;
> it's
> a question of whether the cost of adding exception specifications to
> every
> function (and the ripple-effect updates when a low-level function's
> exception specification is widened and all calling functions'
> specifications must also widen) is worth the benefit of occasionally
> being
> able to know exactly what is thrown.

I think I'm against checked exceptions as they exist in Java, though I
don't know enough to conclude at this time. However, what I will do is
pursue the following "concept / idea in progress" as my new preferred
way of solving this static-checked exceptions dilemma, though it's
probably academic at this time for C++. (Maybe some cool new language
could take this idea and run with it, or the next major revision to C+
+.)


Proposal:
- The throws specification of a function can include the keyword auto.
Ex:
void foo() throw(auto);
void bar() throw(std::bad_alloc, auto);
void baz() throw(auto, std::bad_alloc);
- A function without an explicit C++ source throws specification is
equivalent to giving it a throws "auto" throws specification. Ex: The
following two function declarations are equivalent. In particular,
they are both allowed in the same translation unit:
void foo();
void foo() throw(auto);
just as the following two declarations are equivalent:
void bar();
void bar(void);
- When a function is compiled with a C++ source throws specification,
that throws specification is added to the compiled object code. In
particular, "auto" is added to the compiled object code in the throws
specification of the function.
- Function pointers can be declared with a throws specification.
Function pointers are convertible and can be assigned to function
pointers with an equal or less restrictive throws specification.
Function pointer declarations without a throws specification mean
"throws anything". For a function foo with a C++ source throws
specification including "auto", the type of "& foo" is a function
pointer of "throws anything".
- When the linker links object files together, it will create a call
graph. For each function with a C++ source throws specification with
"auto" (or no C++ source throws specification), it will traverse the
call graph down, figuring out every single function it can call,
directly or indirectly. It will then determine a minimal throws
specification for that function, and append that to any exceptions in
the C++ source throws specification. For each function with a C++
source throws specification without "auto", if the linker finds that
an exception can be thrown which is not in the C++ source throws
specification, it will issue a diagnostic. (Note that this could
probably be optimized to something like a bottom up traversal of the
graph, from leafs to roots.)
- If required, change the appropriate standard libraries to have the
correct C++ source throws specifications.

Cycles in the call graph deserve special mention here. That a function
can call another function which can call itself cannot add any new
exceptions, so such links in the call graph can be ignored when
determining the minimal throws specification for throws "auto"
functions and when issuing the new diagnostic described in this
proposal.


This achieves what both sides what. For a vast majority of the
functions, we don't have to care what can be thrown through it, just
that it is correct if an exception is thrown through it. For the
places which matter, we can manually specify throws specifications,
aka header files which are given to users of our library.

I would argue against unchecked exceptions with this scheme. All
exceptions would be checked. For the C++ world, I would guess there's
less than half a dozen exceptions in any project that you would want
unchecked anyway, so it's not terribly hard to just list them out on
the small number of functions with C++ source throws specifications.
Offhand, I can think of only std::bad_alloc and
boost::thread_interrupted.

The biggest problem is that this proposal would almost certainly
require a large change to all C++ implementations.

Finally, it is also a "breaking change" to C++ proper. This proposal
would be relatively benign to code not using function pointers and
throws specifications, but it would probably require the addition of a
few well placed "catch (...)" for code using function pointers and
throws specifications.

Anyone have any comments or thoughts on its workability, feasibility?
Any additions? Any glaring holes which I missed?

Eugene Gershnik

unread,
Dec 10, 2008, 10:10:20 AM12/10/08
to
On Dec 8, 2:57 pm, blargg....@gishpuppy.com (blargg) wrote:
> Eugene Gershnik wrote:
>
> > What compile-time exception specifications give you is an ability to
> > have the compiler check the same things that you would have to put in
> > the docs and verify manually *anyway*.
>
> [...]
>
> What about foo's implementation changing in other ways that could be
> incompatible with some code out there? Why should changes in what
> exceptions are thrown get special treatment by a compiler? It's not simply
> a question of whether exception specifications are sometimes useful; it's
> a question of whether the cost of adding exception specifications to every
> function (and the ripple-effect updates when a low-level function's
> exception specification is widened and all calling functions'
> specifications must also widen) is worth the benefit of occasionally being
> able to know exactly what is thrown.

Sigh. These same arguments (recurring all over this thread) are what I
tried to address in the posts above but somehow I just cannot get the
point through.

Let's try another approach. Take a look at any library in Boost,
standard library or any module of your own code. From any of the top
level, exposed functions draw a tree of function calls until you hit
another module boundary or just "plain ints". Now look at the height
of this tree. In most cases it will be in single digits. (I'd
appreciate any counter examples)
This height is precisely what should be the maximum extent of the
ripple-effect you mention.
The module interface, which is the contract with your clients should
have its exception specifications designed and mostly frozen from the
beginning. Inside the module you are free to change the implementation
and, yes, it might involve changing exception specs of the internal
functions. But any propagation of these changes must somehow stop at
the module boundary. There you need to either handle new exceptions,
translate them or do something else to conform to the interface you
published to your clients. If you can't do any of the above in a
reasonable way most likely you have found a design problem.
Note that it doesn't matter if you have a language that supports
compile-time exception specifications or current C++. The principle
above stays the same. Your module interface includes exceptions this
module can emit, which in C++ are specified in documentation. (In case
of template code these exceptions are specified in terms of what
operations on T are used by each method and what they can throw but
the principle stays the same). You cannot violate this interface or
you will break your clients.
All compile-time ES add to this picture is the enforcement by the
compiler.


--
Eugene

Gerhard Menzl

unread,
Dec 10, 2008, 10:20:27 AM12/10/08
to
Karl Uppiano wrote:

> I think that depends on how statically checked exceptions are
> ultimately implemented. You would have to prove to me that the set is
> unbounded, and that there was no way to solve that.

The first proof is easy. In

template <typename T> class C
{
//...
};

the set of argument types for T is, by definition, unbounded. Therefore,
the set of exceptions is unbounded. As for the second proof, it's up to
you to prove the opposite.

> As I have said repeatedly, there should be ways to work around it.
> In Java, you can throw an exception derived from RuntimeException and
> you don't have to declare it. The compiler won't check it, and at
> runtime, it will just go sailing right past anyone who doesn't
> otherwise know it's coming. It isn't considered a best practice to use
> this design pattern without careful thought, but the option exists in
> Java.

In C++, this option is the norm. RuntimeException in Java is the
solution to a problem that C++ doesn't have because it doesn't have
static checking of exception specification. This is a bit like proposing
diesel-powered refrigerators, and upon being pointed to the problem of
indoor exhaust fumes saying "but FossileCool comes with an exhaust
filter - a feature that electric fridges cannot offer!".

> This particular solution is currently unavailable in C++ because
> the language lacks a standard set of exception classes, and C++ is
> class-agnostic.

I don't understand what you mean by "class-agnostic", but it is
certainly not true that "the language lacks a standard set of exception
classes". There is std::exception and several exception classes, such as
std::bad_alloc, derived from it.

In another posting, you wrote:

> I'll grant you, it is harder in C++ than in some other languages,
> especially for legacy compatibility with things such as the std
> template library. Perhaps it is impossible, but I would welcome a
> solution if it could address most of the common use cases, and perhaps
> be disabled for the corner cases.

The C++ Standard Library is not a legacy thing, it is an integral part
of the language. It is also used in most modern C++ programs and far
from being a corner case. To illustrate the point with another analogy:
imagine I were to propose a change to Java that would not work with
java.lang.object, and then saying, okay, let's put in a workaround for
this corner case.

Your argument is also beside the point because the problems regarding
static checking affect all (i.e. also newly-written) generic code. The
Standard Library containers are just the most obvious example.


--
Gerhard Menzl

Non-spammers may respond to my email address, which is composed of my
full name, separated by a dot, followed by at, followed by "fwz",
followed by a dot, followed by "aero".

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

David Abrahams

unread,
Dec 10, 2008, 10:39:49 AM12/10/08
to

on Thu Nov 20 2008, DeMarcus <demarcus-AT-hotmail.com> wrote:

> Hi,
>
> Recently I bought the book C++ Coding Standards by Sutter and
> Alexandrescu. The book is good but there's one thing that they comment
> in a way that doesn't feel right. I talk about item 75 in the book.
>
> Item 75 says: "Avoid exception specifications.".
>
> The authors have a lot of good arguments for not using exception
> specifications, but there's one thing they're missing; the
> specifications have a purpose, or at least should have.

Of course every feature in a language *should* have a purpose, but
sometimes, well, they just don't.

> The authors neglect this fact with following argument: "People often
> suggest switching from dynamically checked exception specifications to
> statically checked ones, as provided in Java and other languages. In
> short, that just trades one set of problems for another; users of
> languages with statically checked exception specifications seem to
> equally often suggest switching to dynamically checked ones."
>
> I don't blame the authors, don't take me wrong, but to me it seems like
> the exception specifications need to be fixed when two of the most
> renowned C++ programmers recommend us to avoid them.

Yes; they should be removed.

A little less-glibly, they should be replaced with a statically-checked
"nothrow" specification. Unlike "is this going to be exception A or
exception B," failure to account for nothrow actually affects
correctness in most cases.

> I think statically checked exception specifications (the same way as in
> Java) should be implemented because of three things.
>
> 1. Prefer *compile time* check before run-time.

Some things just don't need to be checked at compile-time. Can you
imagine having to declare every derived class that can come out of a
factory function?

struct Base { virtual ~Base(); };
std::auto_ptr<Base> factory() emits(Derived1, Derived2, ... DerivedN);

It amounts to the same thing for correctness, maintainability, coupling,
etc.: a nightmare.

I usually dislike postings containing lists of links, but in this case
I've been over the argument so many times...

*
http://groups.google.com/group/comp.lang.c++.moderated/msg/c765149dbb040098
* http://tech.groups.yahoo.com/group/boost/message/22807
*
http://groups.google.com/group/comp.lang.c++.moderated/msg/9474fbe0c98d5a4a?
*
http://groups.google.com/group/comp.lang.c++.moderated/msg/9c9d52e31ecbedbd
* http://groups.google.com/group/comp.lang.c++/msg/4752eb5ceeda257a

etc.

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

Martin Bonner

unread,
Dec 10, 2008, 10:39:34 AM12/10/08
to
On Dec 10, 2:48 am, JoshuaMaur...@gmail.com wrote:
[huge snip]

> Anyone have any comments or thoughts on its workability, feasibility?
> Any additions? Any glaring holes which I missed?

It doesn't address the original Stroustrup counter example to
statically checked exceptions:

std::sqrt(double) is documented as throwing std::domain_error for
negative values. Now consider:

inline double hypot(double a, double b) throws()
{
return std::sqrt( a*a + b*b );
}

This function clearly won't ever throw domain_error, but how do you
tell the compiler that? I think to add statically checked exceptions
to C++, you have to add a "throw_cast" which tells the compiler that
the expression will not throw a certain type (or will throw a given
set of types). If the expression /does/ throw, then that is UB.

Similar examples can be constructed for push_back on a vector when you
have already allocated enough space.

Geert-Jan Giezeman

unread,
Dec 10, 2008, 10:33:49 AM12/10/08
to
Joshua...@gmail.com wrote:
>
> I think I'm against checked exceptions as they exist in Java, though I
> don't know enough to conclude at this time. However, what I will do is
> pursue the following "concept / idea in progress" as my new preferred
> way of solving this static-checked exceptions dilemma, though it's
> probably academic at this time for C++. (Maybe some cool new language
> could take this idea and run with it, or the next major revision to C+
> +.)
>
>
> Proposal:
> - The throws specification of a function can include the keyword auto.
> Ex:
> void baz() throw(auto, std::bad_alloc);
> - A function without an explicit C++ source throws specification is
> equivalent to giving it a throws "auto" throws specification.
> - When a function is compiled with a C++ source throws specification,
> that throws specification is added to the compiled object code. In
> particular, "auto" is added to the compiled object code in the throws
> specification of the function.

> - When the linker links object files together, it will create a call


> graph. For each function with a C++ source throws specification with
> "auto" (or no C++ source throws specification), it will traverse the
> call graph down, figuring out every single function it can call,
> directly or indirectly. It will then determine a minimal throws
> specification for that function, and append that to any exceptions in
> the C++ source throws specification. For each function with a C++
> source throws specification without "auto", if the linker finds that
> an exception can be thrown which is not in the C++ source throws
> specification, it will issue a diagnostic. (Note that this could
> probably be optimized to something like a bottom up traversal of the
> graph, from leafs to roots.)

> Anyone have any comments or thoughts on its workability, feasibility?


> Any additions? Any glaring holes which I missed?

I like the direction you are taking: no unchecked exceptions and some
automatic way of keeping track of what can be thrown. I think the
workability would be ok, but I have my doubts about the feasability.

Given the following code (under the proposed extension):

void foo(int i) // 1
{
if (i<0) throw std::invalid_argument("negative argument");
}

void bar(int i) throw()
{
try {
foo(i); // 2
} catch (std::exception &) {
}
foo(i); // 3
}

Given that foo throws an exception itself, which of the following
declarations would be OK?
void foo(in) // nothing here
void foo(int) throw(auto)
void foo(int) throw(std::invalid_argument)
void foo(int) throw(std::exception)
So, does the compiler infer the exceptions thrown by a function?

You say that the linker infers the throws specification by traversing
the call graph. Now, in function bar, call 2) should not lead to any
problem with respect to the no-throw specification, because the (base
class of the) exception thrown by foo is caught. Call 3) should lead to
a diagnostic. It seems that your scheme is a bit too simplistic to deal
with this situation. The exception specification tracer should know
about try blocks and about the hierarchy of exceptions in order to do
its work. Especially in the case of dynamic loading, this may be difficult.


Geert-Jan Giezeman

David Abrahams

unread,
Dec 10, 2008, 1:01:26 PM12/10/08
to

on Wed Dec 10 2008, Eugene Gershnik <gershnik-AT-gmail.com> wrote:

> Let's try another approach. Take a look at any library in Boost,
> standard library or any module of your own code. From any of the top
> level, exposed functions draw a tree of function calls until you hit
> another module boundary or just "plain ints". Now look at the height
> of this tree. In most cases it will be in single digits. (I'd
> appreciate any counter examples)

Just about any code that uses the serialization library will spend 10
levels in that library alone, not to mention the levels of the code
surrounding it.

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Eugene Gershnik

unread,
Dec 11, 2008, 9:56:38 AM12/11/08
to
On Dec 10, 7:39 am, Martin Bonner <martinfro...@yahoo.co.uk> wrote:
> [...] the original Stroustrup counter example to

> statically checked exceptions:
>
> std::sqrt(double) is documented as throwing std::domain_error for
> negative values. Now consider:
>
> inline double hypot(double a, double b) throws()
> {
> return std::sqrt( a*a + b*b );
> }
>
> This function clearly won't ever throw domain_error, but how do you
> tell the compiler that?

And how do you tell this to a maintainer? Write a huge comment in the
best case or just leave the assumption implicit? Consider the version
below:

inline double hypot(double a, double b) throws()
{

try


{
return std::sqrt( a*a + b*b );
}

catch(std::domain_error & )
{
die_immediately_producing_crash_dump();
}
}

This:
1) Guards against maintainer replacing a*a with something that can
produce negative result
2) Guards against possible bugs in callee (unlikely in this case but
very likely with something else being called)
3) Documents your intent in way enforced by the compiler (so it
doesn't get out of sync the way comments always do).

It is also may be slower than the original version on some
implementations.

Personally, I'd take slower but robust version over fast but
potentially buggy one any time. CPUs are cheap, programmer time is
expensive (even in in-sourcing countries). However, I can imagine some
rare situations where you might want to use the faster version and
have some mechanism to suppress static ES checks.

--
Eugene

Joshua...@gmail.com

unread,
Dec 11, 2008, 10:12:25 AM12/11/08
to
On Dec 10, 7:33 am, Geert-Jan Giezeman <ge...@cs.uu.nl> wrote:

Yes, it would have to know about try catch blows, throw statements,
etc. It would not be an easy change to implementations.

Alternatively, the compiler could help out as well. It could include
in the compiled object code
* The specified throws of function foo = exception_2.
* The actual throws of function foo = ((throws of function bar -
exception_1) union (throws of function baz) union (exception_2)) -
(exception_3).

The linker would not have to make any call graphs if the compiler gave
it this.


On Dec 10, 7:39 am, Martin Bonner <martinfro...@yahoo.co.uk> wrote:

> On Dec 10, 2:48 am, JoshuaMaur...@gmail.com wrote:
> [huge snip]
>

> > Anyone have any comments or thoughts on its workability,
> > feasibility?
> > Any additions? Any glaring holes which I missed?
>

> It doesn't address the original Stroustrup counter example to


> statically checked exceptions:
>
> std::sqrt(double) is documented as throwing std::domain_error for
> negative values. Now consider:
>
> inline double hypot(double a, double b) throws()
> {
> return std::sqrt( a*a + b*b );
> }
>
> This function clearly won't ever throw domain_error, but how do you

> tell the compiler that? I think to add statically checked exceptions
> to C++, you have to add a "throw_cast" which tells the compiler that
> the expression will not throw a certain type (or will throw a given
> set of types). If the expression /does/ throw, then that is UB.
>
> Similar examples can be constructed for push_back on a vector when you
> have already allocated enough space.

Hmmm... Having worked with Java for a while, the same problem exists
there.

This is unlike the other attacks I've read in this thread on
statically checked exceptions (though I may have blanked out on this
one when I first read the thread). It's not arguing ease of use,
maintenance, or anything else like that. It's arguing that it's just a
bad idea to start with.

Let me try a thought experiment. Suppose you had some large chunk of
code which produced an input to a function foo() on an object bar.
bar::foo() is documented as returning an error code if the input is
invalid for the current state of the bar object. Now, you can
determine via code review that your code will never produce this
invalid input, and thus you argue that you do not need to check for
the error return code.

I see the previous paragraph as the moral equivalent of your argument
of "No statically checked exceptions because the programmer knows what
he is doing". C++ should let the programmer do what he wants when he
knows what he is doing, but generally we should prefer giving him
tools to prevent himself from accidentally shooting himself in the
foot, ex: type safety, and to bypass it type punning, void pointers,
etc.

In this case, suppose we know that this particular call to sqrt will
not throw an exception. In my scheme, if we do not deal with the
impossible exception, the compiler / linker will complain at us. When
it does, the programmer could put a try-catch (with an release assert
in the catch) to quiet the compiler on this impossible situation. (To
argue against any maintainability objections, if this happens
frequently for this function, the programmer could just write a small
wrapper over the function to catch and release-assert on any thrown
exceptions.)

I think that this statically checked exception scheme would be
exceedingly useful, and I think the counter-argument of Stroustrup is
probably rare enough that the programmer can handle these cases by
squelching the impossible exception with a try-catch-release-assert.

Bart van Ingen Schenau

unread,
Dec 11, 2008, 10:16:11 AM12/11/08
to
Joshua...@gmail.com wrote:

> I think I'm against checked exceptions as they exist in Java, though I
> don't know enough to conclude at this time. However, what I will do is
> pursue the following "concept / idea in progress" as my new preferred
> way of solving this static-checked exceptions dilemma, though it's
> probably academic at this time for C++. (Maybe some cool new language
> could take this idea and run with it, or the next major revision to C+
> +.)
>
> Proposal:
> - The throws specification of a function can include the keyword auto.
> Ex:
> void foo() throw(auto);
> void bar() throw(std::bad_alloc, auto);
> void baz() throw(auto, std::bad_alloc);
> - A function without an explicit C++ source throws specification is
> equivalent to giving it a throws "auto" throws specification. Ex: The
> following two function declarations are equivalent. In particular,
> they are both allowed in the same translation unit:
> void foo();
> void foo() throw(auto);
> just as the following two declarations are equivalent:
> void bar();
> void bar(void);

This will probably create problems when interfacing with other
languages, so I would like to make the following amendment:
- A function with C++ language linkage that does not have an explicit
throws specification is assumed to have the throws
specification 'throw(auto)'. A function with language linkage for some
other language (for example C), without an explicit throws
specification, is assumed to have the throws specification 'throw()'.

As libraries that provide an API consisting of C functions (and taking
pointers to C functions as callbacks) are either written in a language
that does not support C++ exceptions or are designed to be used from
such a language, it makes no sense to assume any exception could
successfully cross the module boundary. My amendment allows this to be
integrated into the static checking of exception specifications.

> - When a function is compiled with a C++ source throws specification,
> that throws specification is added to the compiled object code. In
> particular, "auto" is added to the compiled object code in the throws
> specification of the function.

Three remarks here:
- The annotation for the possibly thrown types should also have the
possibility to specify types that will explicitly *not* be thrown,
because they are caught within the function and nothing after the
catch() clause could throw them again.

- The annotation 'auto' should only be placed in the object file if the
function calls some other function with a throw(auto) specification,
where an (currently) unknown exception can escape the current function.

- If a function contains a reachable throw expression, then the compiler
will verify that the exception thrown by that expression is acceptable
according to the throws specification. If the throws specification
contains the auto keyword, the throw exception type is added to the
annotation in the object code (if it was not explicitly listed
already).

> - Function pointers can be declared with a throws specification.
> Function pointers are convertible and can be assigned to function
> pointers with an equal or less restrictive throws specification.
> Function pointer declarations without a throws specification mean
> "throws anything". For a function foo with a C++ source throws
> specification including "auto", the type of "& foo" is a function
> pointer of "throws anything".
> - When the linker links object files together, it will create a call
> graph. For each function with a C++ source throws specification with
> "auto" (or no C++ source throws specification), it will traverse the
> call graph down, figuring out every single function it can call,
> directly or indirectly. It will then determine a minimal throws
> specification for that function, and append that to any exceptions in
> the C++ source throws specification. For each function with a C++
> source throws specification without "auto", if the linker finds that
> an exception can be thrown which is not in the C++ source throws
> specification, it will issue a diagnostic. (Note that this could
> probably be optimized to something like a bottom up traversal of the
> graph, from leafs to roots.)

As the linker will typically not see any actual source code (and
sometimes can not possibly see it), I would rewrite this point such
that the linker fills in the 'auto' annotations for the throws
specifications in the object file and verifies that any completed
specification (all unknown exceptions are filled in) is not more
restrictive than the union of specifications of the functions it
directly calls.

That leaves one problem with how to deal with object files that don't
contain exception specifications (because they were compiled before
introduction of this feature, or because the translator for another
language made them).
I would resolve that issue in this way: For identifiers exported by such
an object file that can be used from other languages than C++ without
intimate knowledge about compiler-internals (like the name mangling
scheme), it should be assumed that such functions throw no exceptions.
Otherwise, the function must be assumed to be able to throw anything. If
this assumption causes the check for thrown and declared exceptions to
fail on some other function, this should be reported with a non-fatal
diagnostic.

> - If required, change the appropriate standard libraries to have the
> correct C++ source throws specifications.
>
> Cycles in the call graph deserve special mention here. That a function
> can call another function which can call itself cannot add any new
> exceptions, so such links in the call graph can be ignored when
> determining the minimal throws specification for throws "auto"
> functions and when issuing the new diagnostic described in this
> proposal.
>
>
>
> This achieves what both sides what. For a vast majority of the
> functions, we don't have to care what can be thrown through it, just
> that it is correct if an exception is thrown through it. For the
> places which matter, we can manually specify throws specifications,
> aka header files which are given to users of our library.
>
> I would argue against unchecked exceptions with this scheme. All
> exceptions would be checked. For the C++ world, I would guess there's
> less than half a dozen exceptions in any project that you would want
> unchecked anyway, so it's not terribly hard to just list them out on
> the small number of functions with C++ source throws specifications.
> Offhand, I can think of only std::bad_alloc and
> boost::thread_interrupted.
>
> The biggest problem is that this proposal would almost certainly
> require a large change to all C++ implementations.

I think one of the biggest hurdles will be that, with this proposal a
large change must be made to the linker. To my understanding, that was
also what has kept 'export' from being adopted widely, so it is a very
big hurdle.

>
> Finally, it is also a "breaking change" to C++ proper. This proposal
> would be relatively benign to code not using function pointers and
> throws specifications, but it would probably require the addition of a
> few well placed "catch (...)" for code using function pointers and
> throws specifications.

But at least it in not a 'silent breaking' in those cases.

>
> Anyone have any comments or thoughts on its workability, feasibility?
> Any additions? Any glaring holes which I missed?

In addition to the comments made above:
- I like the direction of the proposal.
- This does not cooperate nicely with internal linkage, so that would
have to be removed for functions for the checking to work properly.
Another option would be to implicitly add 'auto' to the specification
for functions with internal linkage and let the compiler resolve that
(as if the function was inlined), but the 'internal linkage' meaning of
static is already deprecated, so...

Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://c-faq.com/
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Nevin :-] Liber

unread,
Dec 11, 2008, 2:11:48 PM12/11/08
to
In article
<a0aed6f8-e64f-421d...@t3g2000yqa.googlegroups.com>,
Joshua...@gmail.com wrote:

> Proposal:
> - The throws specification of a function can include the keyword auto.
> Ex:
> void foo() throw(auto);
> void bar() throw(std::bad_alloc, auto);
> void baz() throw(auto, std::bad_alloc);

What is the difference between:

void foo();
void foo() throw(auto);

void foo() throw(std::bad_alloc, auto);
void foo() throw(auto, std::bad_alloc);


If this were the body of foo:

{
static unsigned u;
if (++u % 2)
throw u;
else
throw std::bad_alloc();
}

I don't see any difference, either at compile time or run time, between
the four declarations.

Could you provide an example that shows the differences between the four
cases?

--
Nevin ":-)" Liber <mailto:ne...@eviloverlord.com> 773 961-1620

Eugene Gershnik

unread,
Dec 11, 2008, 2:13:32 PM12/11/08
to
On Dec 10, 10:01 am, David Abrahams <d...@boostpro.com> wrote:
> on Wed Dec 10 2008, Eugene Gershnik <gershnik-AT-gmail.com> wrote:
>
> > Let's try another approach. Take a look at any library in Boost,
> > standard library or any module of your own code. From any of the top
> > level, exposed functions draw a tree of function calls until you hit
> > another module boundary or just "plain ints". Now look at the height
> > of this tree. In most cases it will be in single digits. (I'd
> > appreciate any counter examples)
>
> Just about any code that uses the serialization library will spend 10
> levels in that library alone, not to mention the levels of the code
> surrounding it.

Well the surrounding code is irrelevant for this discussion.
Presumably it communicates with this library via stable and well
defined interfaces.
With regards to the library itself, I am not familiar with it, and
will take a look, but call tree this deep suggests that there probably
are well-defined sub-modules with fixed interfaces inside. Am I wrong?

--
Eugene

--

Bart van Ingen Schenau

unread,
Dec 11, 2008, 2:11:49 PM12/11/08
to
Joshua...@gmail.com wrote:

> I think that this statically checked exception scheme would be
> exceedingly useful, and I think the counter-argument of Stroustrup is
> probably rare enough that the programmer can handle these cases by
> squelching the impossible exception with a try-catch-release-assert.

Otherwise, we can always introduce a feature that allows the programmer
to tell the compiler 'Yes, I know the function says it can throw X, but
I know better: The function will never throw X here.'
If the programmer uses that feature and messes up, you have an
unexpected exception flying through your system. That should be no
worse than an unexpected exception is now.

Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://c-faq.com/
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

DeMarcus

unread,
Dec 11, 2008, 2:14:15 PM12/11/08
to
David Abrahams wrote:
> on Thu Nov 20 2008, DeMarcus <demarcus-AT-hotmail.com> wrote:
>
>> The authors neglect this fact with following argument: "People often
>> suggest switching from dynamically checked exception specifications to
>> statically checked ones, as provided in Java and other languages. In
>> short, that just trades one set of problems for another; users of
>> languages with statically checked exception specifications seem to
>> equally often suggest switching to dynamically checked ones."
>>
>> I don't blame the authors, don't take me wrong, but to me it seems like
>> the exception specifications need to be fixed when two of the most
>> renowned C++ programmers recommend us to avoid them.
>
> Yes; they should be removed.
>

I think I agree. The best way to solve this issue may actually be, as
suggested earlier in this post, to deprecate exception specifications
and later reintroduce them in a way that will not affect code not using
them.

>
>> I think statically checked exception specifications (the same way as in
>> Java) should be implemented because of three things.
>>
>> 1. Prefer *compile time* check before run-time.
>
> Some things just don't need to be checked at compile-time. Can you
> imagine having to declare every derived class that can come out of a
> factory function?
>
> struct Base { virtual ~Base(); };
> std::auto_ptr<Base> factory() emits(Derived1, Derived2, ... DerivedN);
>
> It amounts to the same thing for correctness, maintainability, coupling,
> etc.: a nightmare.
>

To me exception specifications are used by the compiler as a consistency
check; a higher order of return values if you wish.

A factory is not part of the language but rather a user defined design
pattern that may be arbitrary complex. Of course there must be a way to
disable exception specifications for such situations.

--

Joshua...@gmail.com

unread,
Dec 12, 2008, 12:50:48 AM12/12/08
to
On Dec 11, 11:11 am, "Nevin :-] Liber" <ne...@eviloverlord.com> wrote:
> In article
> <a0aed6f8-e64f-421d-90b4-30177ea54...@t3g2000yqa.googlegroups.com>,

>
> JoshuaMaur...@gmail.com wrote:
> > Proposal:
> > - The throws specification of a function can include the keyword auto.
> > Ex:
> > void foo() throw(auto);
> > void bar() throw(std::bad_alloc, auto);
> > void baz() throw(auto, std::bad_alloc);
>
> What is the difference between:
>
> void foo();
> void foo() throw(auto);
> void foo() throw(std::bad_alloc, auto);
> void foo() throw(auto, std::bad_alloc);
>
> If this were the body of foo:
>
> {
> static unsigned u;
> if (++u % 2)
> throw u;
> else
> throw std::bad_alloc();
>
> }
>
> I don't see any difference, either at compile time or run time, between
> the four declarations.
>
> Could you provide an example that shows the differences between the four
> cases?

I think the best way to make this work is for the compiler to output
to the object file two things: the code specified throws
specification, and the actual things which could be thrown. The actual
things which could be thrown would be a series of set operations where
the base elements of the expression are types thrown in that function
with a "throw" statement and the throws specification of called
function and called function pointers.

unsigned u;
void foo_no_spec
{ if (++u % 2) throw u;
else throw std::bad_alloc();
}
void foo_throws_auto throw(auto)
{ if (++u % 2) throw u;
else throw std::bad_alloc();
}
void foo_throws_auto_unsigned throw(auto, unsigned)
{ if (++u % 2) throw u;
else throw std::bad_alloc();
}
void foo_throws_unsigned_auto throw(unsigned, auto)
{ if (++u % 2) throw u;
else throw std::bad_alloc();
}

foo_no_spec and foo_throws_auto would be equivalent types. You could
typedef them both to the same name. Exactly like "unsigned" and
"unsigned int" have the same type.

foo_throws_auto_unsigned and foo_throws_unsigned_auto also have the
same function type.

foo_no_spec and foo_throws_auto_unsigned have different function
types. You could not typedef them to the same name.

Now, without any optimizations to the basic algorithm, we would get:
foo_no_spec
specified to throw: auto
can throw: (unsigned) union (std::bad_alloc)
foo_throws_auto
specified to throw: auto
can throw: (unsigned) union (std::bad_alloc)
foo_throws_unsigned_auto
specified to throw: unsigned auto
can throw: (unsigned) union (std::bad_alloc)
foo_throws_unsigned_auto
specified to throw: auto unsigned
can throw: (unsigned) union (std::bad_alloc)

The linker will come along, evaluate the "can throw", and make sure
the "can throw" is a subset of the "specified to throw". It will then
attach a third specification to the function, the 'external' throws
specification. This 'external' throws specification is the
specification that will be used when evaluating other "can throw"
specifications of other functions.

In this case, all 4 foo functions will have the same 'external' throws
specification: (unsigned) union (std::bad_alloc), give or take
commutativity of union.

The difference can be shown with this example:
void foo {}
void bar throw (unsigned) {}

foo
specified to throw: auto
can throw: <nothing>
external: <nothing>
bar
specified to throw: unsigned
can throw: <nothing>
external: unsigned

Now, suppose we have another function baz
void baz throw () { bar(); }

baz
specified to throw: <nothing>
can throw: (throws of bar)
The linker will evaluate the "can throw", it will evaluate to
(unsigned), and it will fail the link because unsigned is not a subset
of <nothing>.


In other words, I'm allowing the user to put a throws specification of
something which is not currently thrown. It's like reserving an error
code for future use. When someone publishes an API, they could add
this "fake" extra throws specification. It would never be thrown with
the current version, but if in the future they need to use it, client
code would not break.

I think a simple way to phrase the algorithm is:

When compiling a function, before optimizations and control flow
analysis, analyze all control paths (even impossible ones like if
(false) /*...*/;), and construct the set expression of what can be
thrown from the function, the "can throw". Include the "can throw" and
the code specified throws specification, the "specified to throw", in
the object code.

The linker when linking will make a call graph with the information
provided by the compiler. Start from the leaves, and work your way up.
(See my previous note about cycles in the call graph. Cycles cannot
introduce new exception types, so they can be dealt with in a
reasonable fashion. The actual algorithm would be more complex than
this to handle cycles.) For each node:
- Evaluate the "can throw", and use the "external" specification of
other functions when evaluating a "can throw".
- If it's not a subset of the "specified to throw", where auto is the
set of all things throwable, then fail the link.
- Otherwise, set the "external" to ((evaluated can throw) union
((specified to throw) without auto, if any)).


--

Eugene Gershnik

unread,
Dec 12, 2008, 10:29:41 AM12/12/08
to
On Dec 10, 7:39 am, David Abrahams <d...@boostpro.com> wrote:
> Some things just don't need to be checked at compile-time. Can you
> imagine having to declare every derived class that can come out of a
> factory function?
>
> struct Base { virtual ~Base(); };
> std::auto_ptr<Base> factory() emits(Derived1, Derived2, ... DerivedN);
>
> It amounts to the same thing for correctness, maintainability,
> coupling,
> etc.: a nightmare.

This is a false analogy. When you use interfaces and factories the
clients generally are expected to use the interface and never care
about the derived type. In case of exceptions such useful base
interface does not exist in any language[1]. An no std::exception is
not it. Its "interface" is somewhat equivalent to uber-objects of OO
languages. That is it is mostly useless. (As an aside, you cannot even
clone it or get a decent user-level error message out of it. And,
unfortunately, exceptions don't even have to derive from it. See
Microsoft's _com_error for example.)

In any event, speaking of correctness, maintainability and coupling,
*every* decent library out there (in every language) already supplies
"exception specifications" for all externally visible functions in its
documentation. Actually not having this information is a sure sign of
a bad library. Of course, these ES don't do what people naively expect
them to do, for example list *all* possible exceptions/errors (usually
they list only the 'significant' ones). Still, apparently this
information is necessary and somebody has to work on compiling and
maintaining this documentation anyway. When he gets it wrong people
fill the internet with question like 'Why FooBar API doesn't return
E_PROBLEM when documentation says it should?'. So why would it be
wrong to have the compiler help this poor guy? ;-)

[1] - Given the poor record of 'universal' error codes I suspect such
interface is simply impossible to create.

--
Eugene


--

David Abrahams

unread,
Dec 12, 2008, 7:53:51 PM12/12/08
to

What do you mean by "to me...?" What compiler uses them that way?

> A factory is not part of the language but rather a user defined design
> pattern that may be arbitrary complex. Of course there must be a way to
> disable exception specifications for such situations.

I don't think you understand me at all. Let me try again:

A language change that required you to change this legal C++03:

Base* f();

into

Base* f() emits(Derived1, Derived2, ... DerivedN);

where the emits(...) clause enumerates all the possible dynamic types of
the expression "*f()"

is very similar to a language change that required you to change this
legal C++03:

void f();

into

void f() throws(E1, E2, E3, .. EN);

where the throws(...) clause enumerates all the possible dynamic types
of the thrown exception.

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

David Abrahams

unread,
Dec 12, 2008, 7:52:21 PM12/12/08
to

on Fri Dec 12 2008, Eugene Gershnik <gershnik-AT-gmail.com> wrote:

> On Dec 10, 7:39 am, David Abrahams <d...@boostpro.com> wrote:
>> Some things just don't need to be checked at compile-time. Can you
>> imagine having to declare every derived class that can come out of a
>> factory function?
>>
>> struct Base { virtual ~Base(); };
>> std::auto_ptr<Base> factory() emits(Derived1, Derived2, ...
>> DerivedN);
>>
>> It amounts to the same thing for correctness, maintainability,
>> coupling,
>> etc.: a nightmare.
>
> This is a false analogy.

Disagreed.

> When you use interfaces and factories the clients generally are
> expected to use the interface and never care about the derived type.

Exactly.

> In case of exceptions such useful base interface does not exist in any
> language[1]. An no std::exception is not it. Its "interface" is
> somewhat equivalent to uber-objects of OO languages. That is it is
> mostly useless.

In the case of exceptions, the vast majority of clients are expected to
use the (empty) interface.

> (As an aside, you cannot even clone it

That's fixed in C++0x, for all exceptions.

> or get a decent user-level error message out of it.

For decent user-level error messages, you'd better not try to build
formatting into the exception object anyhow.

> And, unfortunately, exceptions don't even have to derive from it.

Why should they have to? The common interface is empty.

> In any event, speaking of correctness, maintainability and coupling,
> *every* decent library out there (in every language) already supplies
> "exception specifications" for all externally visible functions in its
> documentation. Actually not having this information is a sure sign of
> a bad library. Of course, these ES don't do what people naively expect
> them to do, for example list *all* possible exceptions/errors (usually
> they list only the 'significant' ones). Still, apparently this
> information is necessary and somebody has to work on compiling and
> maintaining this documentation anyway. When he gets it wrong people
> fill the internet with question like 'Why FooBar API doesn't return
> E_PROBLEM when documentation says it should?'.

Interesting. I've never, ever seen such a question asked about a C++
interface that uses exceptions.

> So why would it be wrong to have the compiler help this poor guy? ;-)

Because the cost of taking advantage of that help outweighs any
correctness advantages it might offer, which incidentally are very few.

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Karl Uppiano

unread,
Dec 13, 2008, 5:22:38 PM12/13/08
to
"Gerhard Menzl" <clcppm...@this.is.invalid> wrote in message
news:gho3nq$rue$1...@news.datemas.de...

> Karl Uppiano wrote:
>
>> I think that depends on how statically checked exceptions are
>> ultimately implemented. You would have to prove to me that the set is
>> unbounded, and that there was no way to solve that.
>
> The first proof is easy. In
>
> template <typename T> class C
> {
> //...
> };
>
> the set of argument types for T is, by definition, unbounded. Therefore,
> the set of exceptions is unbounded. As for the second proof, it's up to
> you to prove the opposite.

Sorry it took me so long to respond. I had to go off and think about this a
bit. I think I see the problem. We are working from different premises. I
think you are working from the premise that statically checked exceptions
(SCEs) are unworkable, and thus the feature is not worthy of being part of a
serious software development language.

I am working from the premise that there is usually no perfect solution to
any non-trivial problem, but that the ability to more fully express the API
in a language-aware way can make the code more self-documenting, can be more
robust and easier to maintain. I expressed confidence that the people
responsible for maintaining the C++ specification would be able to maximize
the cases where the feature is beneficial, and minimize the cases where the
feature is unworkable, and also provide un-burdensome ways to opt out in the
latter situation. As such, I feel it is worthy of inclusion in a serious
software development language.

Many years ago, a colleague and I were trying to solve a differential
equation relating to an electronic circuit that we were designing. Progress
was very slow, and we finally swallowed our pride and solved it numerically.
My colleague said "The set of differential equations that cannot be solved
analytically is much larger than the set of DEs that *can* be solved
analytically. Fortunately, both sets are unbounded, so the ability to solve
DEs analytically is still a useful skill to have". I think SCEs might fit
into a category like that.

>> As I have said repeatedly, there should be ways to work around it.
>> In Java, you can throw an exception derived from RuntimeException and
>> you don't have to declare it. The compiler won't check it, and at
>> runtime, it will just go sailing right past anyone who doesn't
>> otherwise know it's coming. It isn't considered a best practice to use
>> this design pattern without careful thought, but the option exists in
>> Java.
>
> In C++, this option is the norm. RuntimeException in Java is the solution
> to a problem that C++ doesn't have because it doesn't have static checking
> of exception specification. This is a bit like proposing diesel-powered
> refrigerators, and upon being pointed to the problem of indoor exhaust
> fumes saying "but FossileCool comes with an exhaust filter - a feature
> that electric fridges cannot offer!".

Well okay, except that I was suggesting that C++ take a page from the Java
play book. It works reasonably well. To wit: deprecate the existing C++
"throw" keyword (as a declaration) and create a new "throws" keyword that
works with a hierarchy of new checked exceptions. Classes directly or
indirectly derived from std::checked_exception : public std::exception would
always be checked. If you throw these, you would have to declare them using
"throws". If someone else throws them, you would have to handle them, or
declare them to be thrown.

Other posts on this thread have proposed various ways of dealing with
templates. Since the template designer has no idea what type of class will
use the template, it is not usually practical explicitly to declare
exceptions thrown by T. Perhaps some automatic compiler mechanism could find
the union (in the set theory sense) of checked exceptions thrown by the
template and thrown by T and emit warnings if checked exceptions are
declared but not handled.

Anything thrown, but not derived from std::checked_exception would be
unchecked. Standard libraries and templates based on existing exception
types would be unchecked and work as always. The "throw()" or "throws()"
syntax could still declare no exceptions will be thrown. Finally, if you
really hate the warnings about the new exceptions being required to be
caught or declared, you could turn them off. Maybe they're off by default.
I'm sure there are details to be worked out, but you get the idea.

>> This particular solution is currently unavailable in C++ because
>> the language lacks a standard set of exception classes, and C++ is
>> class-agnostic.
>
> I don't understand what you mean by "class-agnostic", but it is certainly
> not true that "the language lacks a standard set of exception classes".
> There is std::exception and several exception classes, such as
> std::bad_alloc, derived from it.

By class agnostic, I mean that currently, the C++ compiler does not change
its warning behavior based on exception type declarations in the way I
described above. I realize std::exception is a standard exception type, but
the language proper isn't aware of it, and having std::exception as a
standard base exception isn't all that useful when you can throw anything
and everything.

> In another posting, you wrote:
>
>> I'll grant you, it is harder in C++ than in some other languages,
>> especially for legacy compatibility with things such as the std
>> template library. Perhaps it is impossible, but I would welcome a
>> solution if it could address most of the common use cases, and perhaps
>> be disabled for the corner cases.
>
> The C++ Standard Library is not a legacy thing, it is an integral part of
> the language. It is also used in most modern C++ programs and far from
> being a corner case. To illustrate the point with another analogy: imagine
> I were to propose a change to Java that would not work with
> java.lang.object, and then saying, okay, let's put in a workaround for
> this corner case.

I was hoping it wouldn't be that extreme. If it really is, and if the C++
oracles truly cannot mitigate that, then it will not come to pass.

> Your argument is also beside the point because the problems regarding
> static checking affect all (i.e. also newly-written) generic code. The
> Standard Library containers are just the most obvious example.

As I mentioned above, I was hoping that there would be some kind of a
solution for templates. If there really isn't, then again, it will not come
to pass.


--

DeMarcus

unread,
Dec 14, 2008, 9:32:32 PM12/14/08
to
David Abrahams wrote:
> on Thu Dec 11 2008, DeMarcus <demarcus-AT-hotmail.com> wrote:
>> To me exception specifications are used by the compiler as a consistency
>> check; a higher order of return values if you wish.
>
> What do you mean by "to me...?" What compiler uses them that way?
>

Forgive my unclear sentence. I meant "To me exception specifications
_should_be_ used by the compiler as a consistency check...".

>> A factory is not part of the language but rather a user defined design
>> pattern that may be arbitrary complex. Of course there must be a way to
>> disable exception specifications for such situations.
>
> I don't think you understand me at all. Let me try again:
>
> A language change that required you to change this legal C++03:
>
> Base* f();
>
> into
>
> Base* f() emits(Derived1, Derived2, ... DerivedN);
>
> where the emits(...) clause enumerates all the possible dynamic types of
> the expression "*f()"
>
> is very similar to a language change that required you to change this
> legal C++03:
>
> void f();
>
> into
>
> void f() throws(E1, E2, E3, .. EN);
>
> where the throws(...) clause enumerates all the possible dynamic types
> of the thrown exception.
>

I know there are situations where a function can throw almost what so
ever, and there must be an easy way to pass such exceptions on. Already
in my first post I suggested a way to pass on critical exceptions like
for instance std::bad_alloc.

However, your example is a bit misleading since only the imagination
should limit the types of dynamic classes returned from a factory
meanwhile the same approach for exceptions most certainly leads to
unmaintainable code.


--

David Abrahams

unread,
Dec 15, 2008, 4:12:28 PM12/15/08
to

on Sun Dec 14 2008, DeMarcus <demarcus-AT-hotmail.com> wrote:

> David Abrahams wrote:
>> on Thu Dec 11 2008, DeMarcus <demarcus-AT-hotmail.com> wrote:
>>> To me exception specifications are used by the compiler as a consistency
>>> check; a higher order of return values if you wish.
>>
>> What do you mean by "to me...?" What compiler uses them that way?
>>
>
> Forgive my unclear sentence. I meant "To me exception specifications
> _should_be_ used by the compiler as a consistency check...".

OK, I understand you're in favor of some form of static checking.

>>> A factory is not part of the language but rather a user defined design
>>> pattern that may be arbitrary complex. Of course there must be a way to
>>> disable exception specifications for such situations.
>>
>> I don't think you understand me at all. Let me try again:
>>
>> A language change that required you to change this legal C++03:
>>
>> Base* f();
>>
>> into
>>
>> Base* f() emits(Derived1, Derived2, ... DerivedN);
>>
>> where the emits(...) clause enumerates all the possible dynamic types of
>> the expression "*f()"
>>
>> is very similar to a language change that required you to change this
>> legal C++03:
>>
>> void f();
>>
>> into
>>
>> void f() throws(E1, E2, E3, .. EN);
>>
>> where the throws(...) clause enumerates all the possible dynamic types
>> of the thrown exception.
>>
>
> I know there are situations where a function can throw almost what so
> ever, and there must be an easy way to pass such exceptions on.

That's not my point at all. My point is that, just as the immediate
caller (and its caller, and its caller's caller) generally has no use
for the knowledge of exactly which of an unbounded set of derived
classes is being returned from a factory function, so the immediate
caller of a function that can throw an exception has no use for the
knowledge of which of an unbounded set of possible exceptions is being
thrown. Knowing the possible specific exception types doesn't normally
have any impact at all on the correctness of calling code, except at the
specific point where exceptions are translated or reported, and even
then, the specific type may not matter much.

The idea that, at the end of a long chain of exceptions, one might do
the equivalent of a dynamic_cast to find out which specific exception
was thrown in order to report or translate it doesn't bother me nearly
as much as the cost of manipulating the exception specifications at all
those intermediate layers to keep them consistent.

Test: have you ever encountered a serious bug that made you say, "if
only I had statically-checked exception specifications, this would've
been avoided?" If so, I'd like to hear about it.

If we really need a way to statically check exception specifications
(other than the nothrow specification), I would suggest the
specifications be added to namespaces (or modules, if we ever get those)
and not enforced at the granularity of single functions. That's
actually a feature I might be able to support.

> Already in my first post I suggested a way to pass on critical
> exceptions like for instance std::bad_alloc.

Who decides if an exception is "critical?"

> However, your example is a bit misleading since only the imagination
> should limit the types of dynamic classes returned from a factory
> meanwhile the same approach for exceptions most certainly leads to
> unmaintainable code.

Assuming only the current language features, why do you assert that a
proliferation of exception types will make code unmaintainable?

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

DeMarcus

unread,
Dec 16, 2008, 8:31:46 AM12/16/08
to
David Abrahams wrote:
>
> OK, I understand you're in favor of some form of static checking.
>

Yes, I would like to be able to check at least some exceptions in
compile-time.


>> I know there are situations where a function can throw almost what so
>> ever, and there must be an easy way to pass such exceptions on.
>
> That's not my point at all. My point is that, just as the immediate
> caller (and its caller, and its caller's caller) generally has no use
> for the knowledge of exactly which of an unbounded set of derived
> classes is being returned from a factory function, so the immediate
> caller of a function that can throw an exception has no use for the
> knowledge of which of an unbounded set of possible exceptions is being
> thrown. Knowing the possible specific exception types doesn't normally
> have any impact at all on the correctness of calling code, except at the
> specific point where exceptions are translated or reported, and even
> then, the specific type may not matter much.
>

I totally agree with you that there is intermediate code that has no use
of knowing about exceptions thrown through them. The best example is
template containers. That pass-on problem is something that has to be
solved in a way satisfying both pro- and con- static exception
programmers. (see more below).

Still I would like to try answer your factory example to see if I
understood it. If you return an instance from a factory of type Base*
and has declared for instance Base::calculatePI() throw (OutOfControl)
then that would mean that the programmer tells everyone implementing
Base that it is very important that OutOfControl is there.

Then I think you were referring to the case where we derive from Base in
for instance PocketCalculator : public Base and we want to implement
PocketCalculator::calculatePI() throw (OutOfControl, BatteryEmpty) then
we should still be able to use Base* without caring about BatteryEmpty
that would pass through the system, but in the same time we do a
dynamic_cast<PocketCalculator*> and use calculatePI we would need to
handle BatteryEmpty as well.


>
> Test: have you ever encountered a serious bug that made you say, "if
> only I had statically-checked exception specifications, this would've
> been avoided?" If so, I'd like to hear about it.
>

First of all; those are the bugs you never want to encounter since they
will show up as an angry mail from your customer.

And yes, I have encountered such bugs during some Java projects. The
problem with static checking in Java is very good described in the Bruce
Eckel article provided by Marlow Andrew in this thread.
http://www.mindview.net/Etc/Discussions/CheckedExceptions

In that project I had an exception I thought "It never come that often,
and I don't really know how to handle it right now", and then I
swallowed it (described in the article). However, that swallowing at
least allowed me to log the bug and do a graceful shutdown so I had a
chance to go back to the code and think that problem through. And the
best of all; it puts a pressure on me as a programmer that I'm sloppy
here swallowing exceptions. I then know I'm doing something bad and put
the problem on my todo list.

As another answer to your question I will mention a similar argument as
Eugene Gershnik wrote in this thread; that the exception specifications
help you check whether you follow the documentation.


>> Already in my first post I suggested a way to pass on critical
>> exceptions like for instance std::bad_alloc.
>
> Who decides if an exception is "critical?"
>

That's also a good point. When it comes to for instance the STL there
may be a lot of opinions here. Nevertheless, at least for me there is at
least a distinction between error exceptions and problem exceptions
where errors are show stoppers and problems should be expected in an
application, caught and handled appropriately. Preferably with the
compiler to your help.


>> However, your example is a bit misleading since only the imagination
>> should limit the types of dynamic classes returned from a factory
>> meanwhile the same approach for exceptions most certainly leads to
>> unmaintainable code.
>
> Assuming only the current language features, why do you assert that a
> proliferation of exception types will make code unmaintainable?
>

I meant that the framework should be programmed in a way so you easy can
add whatever module you want whenever you want. But adding exceptions
demands a careful mind.


> If we really need a way to statically check exception specifications
> (other than the nothrow specification), I would suggest the
> specifications be added to namespaces (or modules, if we ever get those)
> and not enforced at the granularity of single functions. That's
> actually a feature I might be able to support.
>

Again, in Eckel's article there is a quote in the end from a C# language
designer where he or she points out that exception specifications are
good under certain circumstances.

As a matter of fact, I believe that the exception specification
situation has a lot of potential to be solved in a really professional
way. Why? Because nobody likes ES as they are designed today. The group
against ES recommend us to avoid them and the group pro ES wants to
change them. So if we can come up with a new exception specification
proposal that pleases both camps then we have actually improved the
language a lot.

During this thread there have been some solution suggestions from people
pro ES. My suggestion is that everyone against ES turn their mind upside
down, try to think as a pro ES and come up with a suggestion what ES
should look like to not affect the programmers that don't want to use
them, or maybe use them differently. What problems will we unavoidable
encounter? Are they solvable?

--

David Abrahams

unread,
Dec 16, 2008, 6:32:01 PM12/16/08
to
on Tue Dec 16 2008, DeMarcus <demarcus-AT-hotmail.com> wrote:

> Again, in Eckel's article there is a quote in the end from a C#
> language designer where he or she points out that exception
> specifications are good under certain circumstances.

Just to follow up, having read Eckel's article and the follow-up
comments, I can find nothing at all there to disagree with. If you
think that article offers anything that substantially differs with my
point-of-view, I think you should read it (and my postings) again.

As an aside, I am not very interested in the effects of such a language
feature on small projects. Small projects are small enough that we can
manage the issues without help from the compiler. I use Python, where
everything is dynamically checked, for small projects all the time.
Static typechecking becomes absolutely essential (to me) as projects get
larger, but static checking of exception specifications (on a
per-function basis) just gets in the way.

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

David Abrahams

unread,
Dec 16, 2008, 6:31:48 PM12/16/08
to
on Tue Dec 16 2008, DeMarcus <demarcus-AT-hotmail.com> wrote:

> David Abrahams wrote:
>>
>> OK, I understand you're in favor of some form of static checking.
>>
>
> Yes, I would like to be able to check at least some exceptions in compile-time.
>
>
>>> I know there are situations where a function can throw almost what so
>>> ever, and there must be an easy way to pass such exceptions on.
>>
>> That's not my point at all. My point is that, just as the immediate
>> caller (and its caller, and its caller's caller) generally has no use
>> for the knowledge of exactly which of an unbounded set of derived
>> classes is being returned from a factory function, so the immediate
>> caller of a function that can throw an exception has no use for the
>> knowledge of which of an unbounded set of possible exceptions is being
>> thrown. Knowing the possible specific exception types doesn't normally
>> have any impact at all on the correctness of calling code, except at the
>> specific point where exceptions are translated or reported, and even
>> then, the specific type may not matter much.
>>
>
> I totally agree with you that there is intermediate code that has no use of knowing
> about exceptions thrown through them. The best example is template
> containers.

I disagree, in the sense that the issue is just as compelling in
non-templated code.

> That pass-on problem is something that has to be solved in a way
> satisfying both pro- and con- static exception programmers. (see more
> below).

That's news to me.

> Still I would like to try answer your factory example to see if I
> understood it. If you return an instance from a factory of type Base*
> and has declared for instance Base::calculatePI() throw (OutOfControl)
> then that would mean that the programmer tells everyone implementing
> Base that it is very important that OutOfControl is there.

Still missing the point, I think. The Base/Derived example is supposed
to be an analogous scenario that *doesn't* use exceptions, to make the
same point about the maintainability of code.

>> Test: have you ever encountered a serious bug that made you say, "if
>> only I had statically-checked exception specifications, this would've
>> been avoided?" If so, I'd like to hear about it.
>>
>
> First of all; those are the bugs you never want to encounter

Of course. Aside: what kind of bugs *do* you want to encounter?

> since they will show up as an angry mail from your customer.
>
> And yes, I have encountered such bugs during some Java projects. The
> problem with static checking in Java is very good described in the
> Bruce Eckel article provided by Marlow Andrew in this thread.
> http://www.mindview.net/Etc/Discussions/CheckedExceptions
>
> In that project I had an exception I thought "It never come that
> often, and I don't really know how to handle it right now", and then I
> swallowed it (described in the article). However, that swallowing at
> least allowed me to log the bug and do a graceful shutdown so I had a
> chance to go back to the code and think that problem through. And the
> best of all; it puts a pressure on me as a programmer that I'm sloppy
> here swallowing exceptions. I then know I'm doing something bad and
> put the problem on my todo list.

It sounds like you're telling me that you deliberately introduced a bug.
The compiler told you an exception would be thrown and instead of
propagating it when you didn't know what to do, you swallowed and logged
it. If the compiler hadn't alerted you to the exception, you wouldn't
have swallowed it.

My claim is that not swallowing the exception would have led to a
program that was no less correct than the one that swallowed it, and
quite possibly more correct. If that's not the case, I claim this is a
highly anomalous example, because it's exceedingly rare that recovery
actions must differ based on the type of exception thrown.

> As another answer to your question I will mention a similar argument
> as Eugene Gershnik wrote in this thread; that the exception
> specifications help you check whether you follow the documentation.

Yes they do, but at what cost? My claim isn't that they have no
benefits. It's that the costs so outweigh the benefits as to be
insignificant.

>>> Already in my first post I suggested a way to pass on critical
>>> exceptions like for instance std::bad_alloc.
>>
>> Who decides if an exception is "critical?"
>
> That's also a good point. When it comes to for instance the STL there
> may be a lot of opinions here. Nevertheless, at least for me there is
> at least a distinction between error exceptions and problem exceptions
> where errors are show stoppers and problems should be expected in an
> application, caught and handled appropriately. Preferably with the
> compiler to your help.

Show stoppers represent programmer errors and should almost never be
handled with exceptions for reasons I've detailed many times over the
years (search the archives here).

>>> However, your example is a bit misleading since only the imagination
>>> should limit the types of dynamic classes returned from a factory
>>> meanwhile the same approach for exceptions most certainly leads to
>>> unmaintainable code.
>>
>> Assuming only the current language features, why do you assert that a
>> proliferation of exception types will make code unmaintainable?
>
> I meant that the framework should be programmed in a way so you easy
> can add whatever module you want whenever you want. But adding
> exceptions demands a careful mind.

I'm sorry, I can't see what you're driving at. Please be specific.

>> If we really need a way to statically check exception specifications
>> (other than the nothrow specification), I would suggest the
>> specifications be added to namespaces (or modules, if we ever get
>> those) and not enforced at the granularity of single functions.
>> That's actually a feature I might be able to support.
>>
>
> Again, in Eckel's article there is a quote in the end from a C#
> language designer where he or she points out that exception
> specifications are good under certain circumstances.

How does that address what I wrote above? It seems as though you're not
even reading it.

> As a matter of fact, I believe that the exception specification
> situation has a lot of potential to be solved in a really professional
> way. Why? Because nobody likes ES as they are designed today. The
> group against ES recommend us to avoid them and the group pro ES wants
> to change them. So if we can come up with a new exception
> specification proposal that pleases both camps then we have actually
> improved the language a lot.

Only if the feature actually works in practice. There can be a great
difference between that and what people can agree to like without having
tried it.

> During this thread there have been some solution suggestions from
> people pro ES. My suggestion is that everyone against ES turn their
> mind upside down,

My suggestion is that you stop thinking of people as being anti-ES.

> try to think as a pro ES and come up with a suggestion what ES should
> look like to not affect the programmers that don't want to use them,
> or maybe use them differently.

So, you're givin no consideration to the suggestion I made above?


--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Eugene Gershnik

unread,
Dec 17, 2008, 8:11:09 PM12/17/08
to
On Dec 15, 1:12 pm, David Abrahams <d...@boostpro.com> wrote:
> on Sun Dec 14 2008, DeMarcus <demarcus-AT-hotmail.com> wrote:
>
>
> Test: have you ever encountered a serious bug that made you say, "if
> only I had statically-checked exception specifications, this would've
> been avoided?" If so, I'd like to hear about it.

Yes. About two weeks ago I was called to help with a bug in a code I
wrote about a year ago. On some customer sites an always-on server
would mysteriously stop authenticating users with an unhelpful error
log message. Turned out that on these particular sites certain network
condition, never encountered by QA, triggered an exception that wasn't
handled until the very high level handler. This level was too far
removed from the operation details and could only do generic handling
which was log and stop further processing. The crucial part is that
the exception was of a particular type that would have been obvious in
Java and handled appropriately (re-establish the connection) in the
lower level code.

I would like to propose an opposite test to anybody who wrote
significant amounts of Java code. Had you ever encountered a situation
where you saw a compiler error due to mismatched ES and had a moment
of "Ah! I better handle this here rather than let it propagate"?

--
Eugene

Eugene Gershnik

unread,
Dec 17, 2008, 8:10:28 PM12/17/08
to
On Dec 12, 4:52 pm, David Abrahams <d...@boostpro.com> wrote:
> on Fri Dec 12 2008, Eugene Gershnik <gershnik-AT-gmail.com> wrote:
>
> > On Dec 10, 7:39 am, David Abrahams <d...@boostpro.com> wrote:
>
> > In case of exceptions such useful base interface does not exist in any
> > language[1]. An no std::exception is not it. Its "interface" is
> > somewhat equivalent to uber-objects of OO languages. That is it is
> > mostly useless.
>
> In the case of exceptions, the vast majority of clients are expected to
> use the (empty) interface.

Then we probably define the word 'client' differently in this context.
For me a client is a piece of code that writes 'catch'. Vast majority
of such clients *should* care about more than an empty interface even
if all they do is log and abort.

> > (As an aside, you cannot even clone it
>
> That's fixed in C++0x, for all exceptions.

Great.

>
> > or get a decent user-level error message out of it.
>
> For decent user-level error messages, you'd better not try to build
> formatting into the exception object anyhow.


Precisely. Which implies that formatting code has to have some
knowledge of the exception type beyond the common interface.

>
> > And, unfortunately, exceptions don't even have to derive from it.
>
> Why should they have to? The common interface is empty.

So how do you handle such an exception by relying on this common
interface?

> > Still, apparently this
> > information is necessary and somebody has to work on compiling and
> > maintaining this documentation anyway. When he gets it wrong people
> > fill the internet with question like 'Why FooBar API doesn't return
> > E_PROBLEM when documentation says it should?'.
>
> Interesting. I've never, ever seen such a question asked about a C++
> interface that uses exceptions.

Well not this exact one, obviously, but a quick Google search on
'vector exceptions' brings questions like

- "What are the exceptions that the vector template throws? For
example, when it runs out of memory?"
- "can I be sure, that push_back throws bad_alloc or a similar std
exception?"

among the results just on the first page. You can also try googling
for 'boost why is exception thrown'.

> > So why would it be wrong to have the compiler help this poor guy? ;-)
>
> Because the cost of taking advantage of that help outweighs any
> correctness advantages it might offer, which incidentally are very few.

This I think is the main point of disagreement. Unfortunately nobody
can prove the truth or falsity of this statement at this time.

--
Eugene

DeMarcus

unread,
Dec 19, 2008, 8:04:26 PM12/19/08
to
David Abrahams wrote:
> Show stoppers represent programmer errors and should almost never be
> handled with exceptions for reasons I've detailed many times over the
> years (search the archives here).
>

std::bad_alloc is a show stopper to many applications and it's nice to
take care of those at a central place, log them and do a graceful
shutdown. Don't you agree with that example?

>>>> However, your example is a bit misleading since only the
>>>> imagination
>>>> should limit the types of dynamic classes returned from a factory
>>>> meanwhile the same approach for exceptions most certainly leads to
>>>> unmaintainable code.
>>> Assuming only the current language features, why do you assert that
>>> a
>>> proliferation of exception types will make code unmaintainable?
>> I meant that the framework should be programmed in a way so you easy
>> can add whatever module you want whenever you want. But adding
>> exceptions demands a careful mind.
>
> I'm sorry, I can't see what you're driving at. Please be specific.
>

When I design a framework I spend weeks of research, designing and
testing the pure interfaces. The design of an interface also includes
the design of its belonging exceptions, hence "adding exceptions demands
a careful mind". The user of an interface should know exactly what to
expect, preferably with the compiler as a help if misused.

When I finally feel I can trust an interface then I use it heavily and
implement whatever derived objects that pop up in my mind and can be
useful features in the application. If suddenly one object would start
to throw something not in the interface specification then there will be
trouble, except if it's something that should be handled in a more
central fashion, possibly with a resulting shutdown/restart of that
module or maybe the whole application.

>>> If we really need a way to statically check exception specifications
>>> (other than the nothrow specification), I would suggest the
>>> specifications be added to namespaces (or modules, if we ever get
>>> those) and not enforced at the granularity of single functions.
>>> That's actually a feature I might be able to support.
>>>
>> Again, in Eckel's article there is a quote in the end from a C#
>> language designer where he or she points out that exception
>> specifications are good under certain circumstances.
>
> How does that address what I wrote above? It seems as though you're
> not
> even reading it.
>

I usually don't mark words, but the full quote from Eckel's article is
"Examination of small programs leads to the conclusion that requiring
exception specifications could both enhance developer productivity and
enhance code quality, but experience with large software projects
suggests a different result -- decreased productivity and little or no
increase in code quality."

It may differ a lot out in the industry but I try to design my
applications in modules with little dependency between each other. One
could see each module as a small program that could benefit from
exception specifications. At least according to the quote above.

I'm not familiar with the namespace ES idea. Please provide an example
or good link. It may be a good basis for further discussions. All
suggestions that could enhance ES are welcome.

>
> My suggestion is that you stop thinking of people as being anti-ES.
>

In this thread actually no one has mentioned they use ES and is pleased
with how they are designed today, except throw (). So the headline
remains valid; "Exception specifications unfortunate". And what about
their future? It feels like that will remain unclear for a long time.

--

David Abrahams

unread,
Dec 19, 2008, 8:15:23 PM12/19/08
to

on Wed Dec 17 2008, Eugene Gershnik <gershnik-AT-gmail.com> wrote:

> On Dec 15, 1:12 pm, David Abrahams <d...@boostpro.com> wrote:
>> on Sun Dec 14 2008, DeMarcus <demarcus-AT-hotmail.com> wrote:
>>
>>
>> Test: have you ever encountered a serious bug that made you say, "if
>> only I had statically-checked exception specifications, this would've
>> been avoided?" If so, I'd like to hear about it.
>
> Yes. About two weeks ago I was called to help with a bug in a code I
> wrote about a year ago. On some customer sites an always-on server
> would mysteriously stop authenticating users with an unhelpful error
> log message. Turned out that on these particular sites certain network
> condition, never encountered by QA, triggered an exception that wasn't
> handled until the very high level handler. This level was too far
> removed from the operation details and could only do generic handling
> which was log and stop further processing. The crucial part is that
> the exception was of a particular type that would have been obvious in
> Java and handled appropriately (re-establish the connection) in the
> lower level code.

Are you describing a sort of failure that shouldn't be reported with
exceptions in the first place, i.e. a condition that must be responded
to very close to the immediate caller of the reporting function?

> I would like to propose an opposite test to anybody who wrote
> significant amounts of Java code. Had you ever encountered a situation
> where you saw a compiler error due to mismatched ES and had a moment
> of "Ah! I better handle this here rather than let it propagate"?

Also a good question.

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

David Abrahams

unread,
Dec 19, 2008, 9:16:49 PM12/19/08
to

on Wed Dec 17 2008, Eugene Gershnik <gershnik-AT-gmail.com> wrote:

> On Dec 12, 4:52 pm, David Abrahams <d...@boostpro.com> wrote:
>> on Fri Dec 12 2008, Eugene Gershnik <gershnik-AT-gmail.com> wrote:
>>
>> > On Dec 10, 7:39 am, David Abrahams <d...@boostpro.com> wrote:
>>
>> > In case of exceptions such useful base interface does not exist in
>> > any
>> > language[1]. An no std::exception is not it. Its "interface" is
>> > somewhat equivalent to uber-objects of OO languages. That is it is
>> > mostly useless.
>>
>> In the case of exceptions, the vast majority of clients are expected
>> to
>> use the (empty) interface.
>
> Then we probably define the word 'client' differently in this context.
> For me a client is a piece of code that writes 'catch'. Vast majority
> of such clients *should* care about more than an empty interface even
> if all they do is log and abort.

Okay, but that makes it a very poor analogy to static function signature
checking. The reason I oppose static checking of exceptions at a
function granularity is precisely *because* the client of any non-empy
interface is so far removed, and separated by many many call layers of
function that have no interest in the non-empty interface.

>> > or get a decent user-level error message out of it.
>>
>> For decent user-level error messages, you'd better not try to build
>> formatting into the exception object anyhow.
>
> Precisely. Which implies that formatting code has to have some
> knowledge of the exception type beyond the common interface.

Yes it does. However, as I've said, while sub-standard error messages
are bad, they don't tend to have any affect on data integrity.

>> > And, unfortunately, exceptions don't even have to derive from it.
>>
>> Why should they have to? The common interface is empty.
>
> So how do you handle such an exception by relying on this common
> interface?

You don't; you do a dynamic downcast. That's essentially what a catch
block is. If every exception author kept to the convention of deriving
from std::exception and publishing their unique what() strings, I'd be
inclined to use something like:

handlers[e.what()](e);

where handlers is a mapping from strings to exception handlers that do
the downcast internally (easily created on-the-fly with a template).

Let's think about what happens when you *are* forced to derive all
exceptions from a given base class and you have statically-checked
exceptions. Then you can write throws(exception_base) and the
specification is always satisfied. It doesn't tell the client anything
interesting about the specific exception type. So in a way, those two
features cancel one another out. If I had to chose one, I'd prefer the
enforced common base because it has some obvious utility (you can rely
on the idiom above and the catch blocks all become simple).

>> > Still, apparently this information is necessary and somebody has to
>> > work on compiling and maintaining this documentation anyway. When
>> > he gets it wrong people fill the internet with question like 'Why
>> > FooBar API doesn't return E_PROBLEM when documentation says it
>> > should?'.
>>
>> Interesting. I've never, ever seen such a question asked about a C++
>> interface that uses exceptions.
>
> Well not this exact one, obviously, but a quick Google search on
> 'vector exceptions' brings questions like
>
> - "What are the exceptions that the vector template throws? For
> example, when it runs out of memory?"
> - "can I be sure, that push_back throws bad_alloc or a similar std
> exception?"

In other words, "what does the documentation say?" Do you consider that
equivalent to "why doesn't the code do what the documentation says?"

> among the results just on the first page. You can also try googling
> for 'boost why is exception thrown'.

None of that looks like the same question to me either.

>> > So why would it be wrong to have the compiler help this poor guy?
>> > ;-)
>>
>> Because the cost of taking advantage of that help outweighs any
>> correctness advantages it might offer, which incidentally are very
>> few.
>
> This I think is the main point of disagreement. Unfortunately nobody
> can prove the truth or falsity of this statement at this time.


--

Dave Abrahams
BoostPro Computing
http://www.boostpro.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Joshua...@gmail.com

unread,
Dec 20, 2008, 2:43:06 PM12/20/08
to
On Dec 19, 5:04 pm, DeMarcus <demar...@hotmail.com> wrote:
> David Abrahams wrote:
> > Show stoppers represent programmer errors and should almost never be
> > handled with exceptions for reasons I've detailed many times over
> > the
> > years (search the archives here).
>
> std::bad_alloc is a show stopper to many applications and it's nice to
> take care of those at a central place, log them and do a graceful
> shutdown. Don't you agree with that example?

I disagree with this blanket generalization. Out of memory errors are
not always "show stopper"s, and I imagine for most nontrivial
applications they should not be something which kills the process,
though the job may not be completable.

A game engine, for example, gets an out of memory error. This is
reasonably bad. There's not much that can be done, but you could
return to the main menu of the program and display to the user an
error and offer to start another game-instance, exit, etc.

Or imagine you're a server handling requests, and you run out of
memory. A thread encounters this error, the exception propagates up
the stack, freeing currently held resources, finally reaching the main
entry point for the thread / job, the out of memory exception is
noticed, and the main thread dishing out jobs can:
1- wait until more jobs have finished before restarting the failed
job,
2- log an error and ignore the job,
3- or kill the process as you suggest.


A real show stopper is when you have an internal logic error, you
perform a find on a data structure for something you know must be in
there, but it's not, or in your string class you know the data is
always kept in a null terminated state, except the code finds that
it's not null terminated. Those are show stoppers. Assertable errors
are show stoppers, and I would rather not have an exception thrown
when I hit an assertable error as is done in Java with the Java
language assert. A failed assert means the code is wrong or the
program is corrupted. Either way I want the process to die now and not
risk more corruption to external things from stack unwinding.

Eugene Gershnik

unread,
Dec 21, 2008, 10:55:26 AM12/21/08
to

Definitely not. The layering of the code is something like follows:

Main app's thread
top level loop with general exception handler
layer1
...
layer3 (--missing catch here--)
Helper Library 1
layer1 (--or maybe here--)
...
layer3
Helper Library 2
layer1
layer2 (--exception thrown here--)

The actual exception is a very low-level thing that is thrown from a
low-level 'dumb' library. All this library knows is to perform certain
operations that in general are expected to complete successfully. When
the operations fail it throws.
This library is in turn used by a higher level library that provides
domain abstractions over the primitive operations. The whole thing is
used by the main application code to authenticate certain credentials.
The points where there is enough knowledge of 'what is going on' to
recover are marked in the diagram. They are pretty far from the code
that raises the exception.

In any event I am curious about your general notion of "a condition
that must be responded
to very close to the immediate caller of the reporting function". How
can you a priori decide
where the condition must be responded to while writing the function
raising the exception?

--
Eugene

--

Eugene Gershnik

unread,
Dec 21, 2008, 10:58:05 AM12/21/08
to
On Dec 19, 6:16 pm, David Abrahams <d...@boostpro.com> wrote:
> on Wed Dec 17 2008, Eugene Gershnik <gershnik-AT-gmail.com> wrote:
>
> The reason I oppose static checking of exceptions at a
> function granularity is precisely *because* the client of any non-empy
> interface is so far removed, and separated by many many call layers of
> function that have no interest in the non-empty interface.

Ok, it is a good argument (and subtly but very different from the
usual misguided complaint about having to 'fix' too many functions
when low-level one changes).
However, isn't this the same for everything that uses strong typing?
For example you might have some int x. Then you carry it through all
of these func(..., int x, ...) just so that in one or two places
something will do x/2 that really cares about the fact that x is an
int. A scripting language programmer might view all of these types in
signatures as an unnecessary thing with no real benefit for functions
that only care about empty interface. How is it different?

> Let's think about what happens when you *are* forced to derive all
> exceptions from a given base class and you have statically-checked
> exceptions. Then you can write throws(exception_base) and the
> specification is always satisfied. It doesn't tell the client anything
> interesting about the specific exception type. So in a way, those two
> features cancel one another out. If I had to chose one, I'd prefer the
> enforced common base because it has some obvious utility (you can rely
> on the idiom above and the catch blocks all become simple).

You can abuse any type system in this way (for example by using void *
in C++ or Object in Java or C#). The fact that you can do it doesn't
by itself mean that the type system is useless.

throws(exception_base)

is as bad as

Object createSocket()

and should not be used in decent code.

> > Well not this exact one, obviously, but a quick Google search on
> > 'vector exceptions' brings questions like
>
> > - "What are the exceptions that the vector template throws? For
> > example, when it runs out of memory?"
> > - "can I be sure, that push_back throws bad_alloc or a similar std
> > exception?"
>
> In other words, "what does the documentation say?" Do you consider
> that
> equivalent to "why doesn't the code do what the documentation says?"

Sure. Both indicate bugs as far as the client is concerned. The only
slight difference is that the first one indicates a documentation bug
while the second might mean a bug in code, documentation or both. (All
of this assuming the person asking had, in fact, read docs before
using code. A non-trivial assumption these days.)

Whether the bug is in the code or in docs it is a bug. It may cause
the programmer to write incorrect code, introduce unexpected behavior
into the final product and cause some user lots of trouble. The end
user couldn't care less what caused the program to malfunction, be it
bad docs, bad code, bad programmer or bad computer.

--
Eugene

--

Joshua...@gmail.com

unread,
Dec 22, 2008, 10:46:27 PM12/22/08
to
On Dec 21, 7:58 am, Eugene Gershnik <gersh...@gmail.com> wrote:
> On Dec 19, 6:16 pm, David Abrahams <d...@boostpro.com> wrote:
>
> > on Wed Dec 17 2008, Eugene Gershnik <gershnik-AT-gmail.com> wrote:
>
> > The reason I oppose static checking of exceptions at a
> > function granularity is precisely *because* the client of any non-empy
> > interface is so far removed, and separated by many many call layers of
> > function that have no interest in the non-empty interface.
>
> Ok, it is a good argument (and subtly but very different from the
> usual misguided complaint about having to 'fix' too many functions
> when low-level one changes).
> However, isn't this the same for everything that uses strong typing?
> For example you might have some int x. Then you carry it through all
> of these func(..., int x, ...) just so that in one or two places
> something will do x/2 that really cares about the fact that x is an
> int. A scripting language programmer might view all of these types in
> signatures as an unnecessary thing with no real benefit for functions
> that only care about empty interface. How is it different?

The distinction in my mind is the difference between normal path code
and error handling code. I would think it quite odd for there to be
functions like you propose, functions which don't care about the type
of their function parameter. It's part of the normal usage of the
function. If in fact it does not care about the type, I'd wager it
could be better off as a template, in which case strong typing on
arguments and return types is still very useful.

I would think for most functions, the type of an argument is very
meaningful for the successful control path, aka useful for most
immediate callers, whereas exception types are only useful for the
error code path, aka generally not useful for the immediate caller.

Put another way, I'm making the argument that most functions do not
need to know about errors, but most functions do need to know about
normal program flow.

Eugene Gershnik

unread,
Dec 23, 2008, 2:28:26 PM12/23/08
to
On Dec 22, 7:46 pm, JoshuaMaur...@gmail.com wrote:
> I would think it quite odd for there to be
> functions like you propose, functions which don't care about the type
> of their function parameter.

How many times do you see something like this

void foo(const baz & b)
{
bar(b, 42);
}

or

const baz & clazz::get_baz()
{
return m_b;
}

These functions don't care about anything in baz but the 'empty
interface' as David called it.
Quite often such forwarding goes on and on for quite a few call layers
until some piece of code actually uses anything specific to 'baz'
object. The only purpose of saying 'baz' (rather than hypothetical
void &) in the functions above is to carry the type information
through for the compiler so that the it can verify that something used
as 'baz' at the end was created as 'baz' in the beginning.

--
Eugene

Brendan

unread,
Dec 24, 2008, 3:34:08 PM12/24/08
to
On Dec 10, 7:20 am, Gerhard Menzl <clcppm-pos...@this.is.invalid>
wrote:

> Karl Uppiano wrote:
>> I think that depends on how statically checked exceptions are
>> ultimately implemented. You would have to prove to me that the set is
>> unbounded, and that there was no way to solve that.
>
> The first proof is easy. In
>
> template <typename T> class C
> {
> //...
> };
>
> the set of argument types for T is, by definition, unbounded.

That is untrue. T is bounded. The //... that you removed determines
the bounds of T. If we use a function f(x) on an x of type T in the
template, then T is bound to only those types for which f(T) is
defined. This is called an "implicit interface" in C++.

Similarly, if we had compile time exception specifications, then the
exception specifications on the member functions of C would limit what
types could be used for T.

So for some member


template <typename T>
class C {

f() throws() {
T o();
o.g();
}
};

Would not compile for a T that defines the default constructor, or T::g
() to throw.

Constraints are placed on T just as much as there are constraints with
run time polymorphic types. Templates are not special, they are just
compile time polymorphism.

Templates allow for easy copying without slicing, so the issue of the
exception specification of the copy constructor and assignment
operator comes up more than in run time polymorphic types, which only
occasionally implement the equivalent "clone" operation.

However, the issue of the exception specification is already
important. Sometimes you want a no throw guarantee from a copy
constructor. Sometimes it is ok to propagate them.

I think you were getting at the case where you want to propagate the
exception. There seem to be two ways to do this. Use the java route
and say you can always throw some class of exceptions that are
unchecked. Memory allocation errors should obviously be in this
category, and that would solve most copy constructor issues.

You could also provide a mechanism for doing type inference on the
exception specification like:

template<typename T>
void f() throws(auto) {
T o();
}

Then if the default constructor for T throws foo, f<T>() is specified
as throwing foo as well.

For more fine grained control, you could allow inference based on a
list of functions.

template<typename T>
void f() throws(T::T(), T::g(), T::operator=(const T&)) {
T o();
o.g();
T p();
p = o;
}

Note that if any of T::T(), T::g(), T::operator=(const T&) have *no*
exception specification, then we have two choices:
1. do type inference on T::T(), etc. This is probably not practical
given how many compilers can't do this kind of analysis outside of a
translation unit. This would be impossible for shared libraries.
2. Make f() unspecified. I think this is the most reasonable thing to
do. Then exception specs only come into play when you have them from
the bottom up, and are ignored
in cases involving legacy code.

The real problem is that for any of this to be useful, we have to
ditch the runtime checks. As long as those checks are there, exception
specs have more overhead than they are worth.

--

David Abrahams

unread,
Dec 28, 2008, 7:03:31 PM12/28/08
to

on Sun Dec 21 2008, Eugene Gershnik <gershnik-AT-gmail.com> wrote:

> I am curious about your general notion of "a condition that must be
> responded to very close to the immediate caller of the reporting
> function". How can you a priori decide where the condition must be
> responded to while writing the function raising the exception?

You can't. You can, however, anticipate that many applications will
need to respond to the condition nearby. Failure to immediately
establish a network connection might be a good example. In those cases,
throwing an exception should usually be left to the caller.

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

David Abrahams

unread,
Dec 28, 2008, 7:04:53 PM12/28/08
to

on Sun Dec 21 2008, Eugene Gershnik <gershnik-AT-gmail.com> wrote:

> On Dec 19, 6:16 pm, David Abrahams <d...@boostpro.com> wrote:
>> on Wed Dec 17 2008, Eugene Gershnik <gershnik-AT-gmail.com> wrote:
>>
>> The reason I oppose static checking of exceptions at a
>> function granularity is precisely *because* the client of any non-empy
>> interface is so far removed, and separated by many many call layers of
>> function that have no interest in the non-empty interface.
>
> Ok, it is a good argument (and subtly but very different from the
> usual misguided complaint about having to 'fix' too many functions
> when low-level one changes).

That may not be a misguided argument if you are doing cost-benefit
analysis.

> However, isn't this the same for everything that uses strong typing?
> For example you might have some int x. Then you carry it through all
> of these func(..., int x, ...) just so that in one or two places
> something will do x/2 that really cares about the fact that x is an
> int. A scripting language programmer might view all of these types in
> signatures as an unnecessary thing with no real benefit for functions
> that only care about empty interface. How is it different?

It's different because:

* unlike ordinary return values, exceptions have an
automatically-attached control flow semantics that tends to skip over
many layers.

* Special recovery or unwinding actions (by which I mean to exclude
error reporting, logging, or translation) for individual exception
types are comparatively rare. It usually does not affect program
state if you handle all exceptions in the same way, without knowing
their individual types. Thus the practicality of destructors, RAII
objects, etc.

These are qualitative differences, not absolutes, and they impact the
cost/benefit analysis of enforced exception specifications. At the
limit, exceptions _can_ be used in a way that nullifies my arguments,
but in general they are not used that way.

>> Let's think about what happens when you *are* forced to derive all
>> exceptions from a given base class and you have statically-checked
>> exceptions. Then you can write throws(exception_base) and the
>> specification is always satisfied. It doesn't tell the client anything
>> interesting about the specific exception type. So in a way, those two
>> features cancel one another out. If I had to chose one, I'd prefer the
>> enforced common base because it has some obvious utility (you can rely
>> on the idiom above and the catch blocks all become simple).
>
> You can abuse any type system in this way (for example by using void *
> in C++ or Object in Java or C#). The fact that you can do it doesn't
> by itself mean that the type system is useless.
>
> throws(exception_base)
>
> is as bad as
>
> Object createSocket()
>
> and should not be used in decent code.

Not so fast. You're missing a signature in the first case. If

Socket createSocket() throws(exception_base)

is really as bad, in your opinion, as

Object createSocket() throws(nothing)

then we have something to discuss. If that is the case, then please
tell me why.

>> > Well not this exact one, obviously, but a quick Google search on
>> > 'vector exceptions' brings questions like
>>
>> > - "What are the exceptions that the vector template throws? For
>> > example, when it runs out of memory?"
>> > - "can I be sure, that push_back throws bad_alloc or a similar std
>> > exception?"
>>
>> In other words, "what does the documentation say?" Do you consider
>> that equivalent to "why doesn't the code do what the documentation
>> says?"
>
> Sure. Both indicate bugs as far as the client is concerned.

Disagreed. The first indicates that the client didn't read the
documentation.

> The only slight difference is that the first one indicates a
> documentation bug while the second might mean a bug in code,
> documentation or both. (All of this assuming the person asking had, in
> fact, read docs before using code. A non-trivial assumption these
> days.)

Yah.

> Whether the bug is in the code or in docs it is a bug. It may cause
> the programmer to write incorrect code, introduce unexpected behavior
> into the final product and cause some user lots of trouble. The end
> user couldn't care less what caused the program to malfunction, be it
> bad docs, bad code, bad programmer or bad computer.

I disagree again. Not all behaviors -- not even all observable ones --
need to be completely specified, for software to be bug-free. I have no
problem with a library that documents that it throws bad_alloc when in
fact it throws some derived class of bad_alloc. Likewise, I have no
problem with a library that documents that it throws an unspecified
exception (when it in fact throws some actual exception type).

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

David Abrahams

unread,
Dec 28, 2008, 7:05:12 PM12/28/08
to

on Mon Dec 22 2008, JoshuaMaurice-AT-gmail.com wrote:

> I'm making the argument that most functions do not need to know about
> errors, but most functions do need to know about normal program flow.

I don't think I agree with that. I would say that most functions don't
need to know about the specific *reasons* for failure of a function they
have called, because there's nothing they could do differently with that
knowledge.

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Eugene Gershnik

unread,
Jan 3, 2009, 12:49:12 PM1/3/09
to
On Dec 28 2008, 4:04 pm, David Abrahams <d...@boostpro.com> wrote:
> on Sun Dec 21 2008, Eugene Gershnik <gershnik-AT-gmail.com> wrote:
>
> > On Dec 19, 6:16 pm, David Abrahams <d...@boostpro.com> wrote:
> >> on Wed Dec 17 2008, Eugene Gershnik <gershnik-AT-gmail.com> wrote:
>
>
> > Ok, it is a good argument (and subtly but very different from the
> > usual misguided complaint about having to 'fix' too many functions
> > when low-level one changes).
>
> That may not be a misguided argument if you are doing cost-benefit
> analysis.

I am not saying it is misguided because "the price is worth paying".
My point is that such cascades generally shouldn't happen if one
designs function interfaces before writing their implementation. When
they do happen (and it should be extremely seldom) they are always a
sign of deep design problems. (see my post from November 21 that
started this sub-thread for more on this issue)
Your argument is deeper because even if I do everything correctly and
do not have cascades the question is why bother with all this work of
translating exceptions and ensuring correct interfaces when 99% of the
functions do not care about the exception type to begin with.

>
> > However, isn't this the same for everything that uses strong typing?

[...]

>
> It's different because:
>
> * unlike ordinary return values, exceptions have an
> automatically-attached control flow semantics that tends to skip over
> many layers.
>
> * Special recovery or unwinding actions (by which I mean to exclude
> error reporting, logging, or translation) for individual exception
> types are comparatively rare. It usually does not affect program
> state if you handle all exceptions in the same way, without knowing
> their individual types. Thus the practicality of destructors, RAII
> objects, etc.
>
> These are qualitative differences, not absolutes, and they impact the
> cost/benefit analysis of enforced exception specifications. At the
> limit, exceptions _can_ be used in a way that nullifies my arguments,
> but in general they are not used that way.

Ok, so basically for you it is a question of the cost vs. benefits of
each type safety feature of the language. In this case you conclude
that costs are bigger than benefits while for normal function
parameters it is the opposite. Though I disagree I can certainly
understand your point of view (just like I can understand why some
people prefer dynamically typed languages). My disagreement can be
summarized as follows:

- The cost is overhyped (though it is certainly far from zero) and the
benefits are undercounted and not appreciated. (Not many Java
programmers appreciate how easy and predictable their error handling
is when using heterogeneous libraries and even different JVMs compared
to the mess we have in C++).
- While error handling code is a very tiny fraction of the entire
codebase its impact on the end product is often disproportionately
high. This I guess is one of the differences between the points of
view of application and library developers. In every place I worked at
a big amount of time (often comparable to 'normal' development) was
devoted to diagnosing and fixing various problems that arise on
customer sites during some kind of 'error situations'. While having
the code base exception/error safe is a huge step forward compared to
the mess we had before this is not nearly enough to ensure customer
happiness and prevent problems.

> Not so fast. You're missing a signature in the first case. If
>
> Socket createSocket() throws(exception_base)
>
> is really as bad, in your opinion, as
>
> Object createSocket() throws(nothing)
>
> then we have something to discuss. If that is the case, then please
> tell me why.

Let's rewrite them in pseudo-C++ to avoid any confusion over using
Java's object reference syntax. What we have is

Socket * createSocket() throws(exception_base);
Object * createSocket() throws(nothing);

where Object is a base class of everything, including Socket,
exception_base is the base class of all exceptions and 'throws' is
evaluated at compile-time.
In this case, yes, both are equally bad for me. The first signature
requires dynamic_cast in almost any handling code (unless it can use
the base interface only) while the second requires dynamic_cast by
anything (possibly many levels above the immediate caller) that tries
to use the socket (again unless it somehow can live only with the
Object interface). Both casts can fail adding an additional error path
to the system.

>
> >> > Well not this exact one, obviously, but a quick Google search on
> >> > 'vector exceptions' brings questions like
>
> >> > - "What are the exceptions that the vector template throws? For
> >> > example, when it runs out of memory?"
> >> > - "can I be sure, that push_back throws bad_alloc or a similar
> >> > std
> >> > exception?"
>
> >> In other words, "what does the documentation say?" Do you consider
> >> that equivalent to "why doesn't the code do what the documentation
> >> says?"
>
> > Sure. Both indicate bugs as far as the client is concerned.
>
> Disagreed. The first indicates that the client didn't read the
> documentation.

I didn't check right now but I am positive that at least in the recent
past no std::vector documentation I routinely use mentioned anything
about exceptions it can emit. Yes you can 'easily' arrive to a more or
less correct answer by considering how vector can be implemented and
looking at concrete implementations but this is not the same as formal
doc guarantee. (Actually given the popularity of complicated 'checked'
implementations these days I am not at all sure what can be thrown
from each vector's method under low memory conditions when such checks
are not disabled)

> > Whether the bug is in the code or in docs it is a bug. It may cause
> > the programmer to write incorrect code, introduce unexpected
> > behavior
> > into the final product and cause some user lots of trouble. The end
> > user couldn't care less what caused the program to malfunction, be
> > it
> > bad docs, bad code, bad programmer or bad computer.
>
> I disagree again. Not all behaviors -- not even all observable ones --
> need to be completely specified, for software to be bug-free.

Definitely. There are two kinds of errors: 'unexpected' and, for lack
of a better term, 'salient'. To see how they differ consider POSIX or
Win32. They are a good case study because both have been around for a
long time and have user community many times larger than probably any
other commonly used library. Usually each function in both interfaces
has something like this in its 'exception specification'.
"When function fails it <sets some error code>. Possible errors
include (but not limited to):
error 1: if foo condition is not met
error 2: if bar doesn't work
..."

What is usually understood (even if not spelled explicitly) is that
the function can fail with absolutely any error code if the conditions
are weird enough. However, some error conditions are so common or
predictable that it is guaranteed that some client software will want
to detect and handle them. These errors are documented, even
standardized, and a failure to obey the documentation is a bug. In
effect these 'salient' errors become a part of the function interface.
Nobody is crazy enough to expect or require that all the rest of
'unexpected' errors be also documented or guaranteed. However, their
type and a way to get more info about their meaning must at least be
specified. So, yes, you are right that not all error have to be
documented but the salient ones do and the unexpected ones have at
least be specified enough to be 'handle-able'.

> I have no
> problem with a library that documents that it throws bad_alloc when in
> fact it throws some derived class of bad_alloc.

This is fine with me too (as well as with Java ES mechanism).

> Likewise, I have no
> problem with a library that documents that it throws an unspecified
> exception (when it in fact throws some actual exception type).

Here I strongly disagree. I would use such a library only if there was
absolutely no alternative. Unspecified exception cannot be handled or
even logged in a stable way. This can potentially cost me far more in
maintenance time and customer goodwill than getting a different
library. Even if the error is not salient at least some info about its
base type (i.e. std::exception) must be specified. For salient errors
one usually needs even more information.

--
Eugene


--

It is loading more messages.
0 new messages