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

PROPOSAL: Facility for optional stricter checking of exception specifications

9 views
Skip to first unread message

apm

unread,
Nov 16, 2001, 3:03:00 PM11/16/01
to
Here's a concise summary of my proposal for stricter exception
specifications:

By using the word 'onlythrow' instead of 'throw', exception
specifications are subject to static checking and single level
propagation. Violations of an onlythrow list are a compilation error.
Such errors only apply to functions that have an onlythrow list.
Functions that do not have an onlythrow list that call routines that
do are not affected. Functions with an onlythrow list may not call
functions with a throw list since such functions might call
unexpected. A compiler that implements onlythrow must ship with a
standard C++ library that uses onlythrow rather than throw in its
exception specifications.

I have a longer document that describes the proposal in detail but I
thought I would see what interest there is first.

Regards,

Andrew M.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

Pavel Kuznetsov

unread,
Nov 17, 2001, 5:04:17 PM11/17/01
to
apm <ap...@student.open.ac.uk> wrote...

> By using the word 'onlythrow' instead of 'throw', exception
> specifications are subject to static checking and single level
> propagation. Violations of an onlythrow list are a compilation error.
> [...]

Since throw specification as is IMHO could be considered having quite
limited utility, I'd prefer having throw specification to follow
onlythrow semantics.

--
Pavel Kuznetsov

[ THE REPLY ADDRESS IS NOT GUARANTEED TO LIVE LONGER THAN FEW WEEKS! ]
[ The permanent address is: pavel <dot> kuznetsov <at> mail <dot> ru ]

Andrew Koenig

unread,
Nov 18, 2001, 6:27:43 AM11/18/01
to
apm> By using the word 'onlythrow' instead of 'throw', exception
apm> specifications are subject to static checking and single level
apm> propagation.

The C++ committee discussed a similar idea in detail during
the early evaluation of exception handling.

The problem is that there are some operations, such as division by
zero, that are permitted but not required to throw exceptions. A
function that used "onlythrow" in its exception specification would
not be able to use any such operations. Moreover, such a function
might well compile under one implementation but not under another.

--
Andrew Koenig, a...@research.att.com, http://www.research.att.com/info/ark

Terje Slettebø

unread,
Nov 18, 2001, 1:47:37 PM11/18/01
to
Hi.

"Andrew Koenig" <a...@research.att.com> wrote in message
news:yu99d72i...@europa.research.att.com...


> apm> By using the word 'onlythrow' instead of 'throw', exception
> apm> specifications are subject to static checking and single level
> apm> propagation.
>
> The C++ committee discussed a similar idea in detail during
> the early evaluation of exception handling.
>
> The problem is that there are some operations, such as division by
> zero, that are permitted but not required to throw exceptions. A
> function that used "onlythrow" in its exception specification would
> not be able to use any such operations.

I agree with the Pavel Kuznetsov that throw specification, as it is now, has
quite limited utility. This is also detailed in Scott Meyer's "Effective
C++"-books. If you get an exception not specified, it calls unexpected,
which default action is to call terminate.

This problem is solved in Java, which does have a static exception checking,
and where therefore the exception specifications are in fact very useful, as
it reports any exceptions not caught, at compile-time.

The way it's done in Java is to differentiate between checked and unchecked
exceptions. Both types can appear in a catch()-block, but only checked
exceptions are required to be checked for. In other words, it won't complain
at compile-time, if you don't check for them.

The reason they can be unchecked, is that they are exceptions that may be
thrown anywhere in the program, such as expressions with division by zero,
where it's deemed too inefficient to require an exception specification for
such exceptions.

Maybe an idea for C++?

C++ is my favourite language, but I think this exception-specification
system in Java is better than the one in C++, where, as it stands in C++, it
doesn't have much use, as it can't detect any violations of exception
specifications, at compile-time, and therefore have to genererate code to
check for this, at run-time, unlike Java.

This also makes exception specifications cost processing, rather than only
being used at compile-time.

Even if it does catch it at runtime, it only transforms an uncaught
exception to a call to terminate, which is rather drastic. Not even local
variable have their destructors called, so this could lead to resource
leakage, or the program's resources being left in an inconsistent state,
when it terminates.

So what have you gained?


I realize (as it also says in the mentioned books), that it can be difficult
for a compiler to discover all exceptions that may be thrown by a function,
to check it against the specification, such as when calling
callback-functions, from the function, where the the callback-function may
have an unknown exception specification. Unless, of course, if you require
that exception specifications are part of the pointer to function
declaration.

However, if there are cases where it's hard, or impossible to detect, at
compile-time, for certain exceptions, then the exceptions thrown that way,
could be regarded as unchecked exceptions.

In short, I think it could be done better than the way it is now, and that
could help the error checking of C++ programs, by performing the checking at
compile-time, rather than run-time.

In addition, if it's caught at run-time, it's really too late to do
something about it, as the exception has already happened, and no handler is
there to catch it, and, in fact, no handler is given the chance to catch it,
even if there would be one able to do it, further up the call-chain.

The unexpected-function is called, anyway. This can throw bad_exception, but
that's also it. The original exception is lost, and can't be caught later.


Regards,

Terje Slettebø

tslettebo at chello dot no.

apm

unread,
Nov 20, 2001, 6:19:37 PM11/20/01
to
Terje Slettebø <tsle...@start.no> wrote in message
news:<_0PJ7.3538$Sa4.5...@news01.chello.no>...

> Hi.
>
> "Andrew Koenig" <a...@research.att.com> wrote in message
> news:yu99d72i...@europa.research.att.com...
> > apm> By using the word 'onlythrow' instead of 'throw', exception
> > apm> specifications are subject to static checking and single level
> > apm> propagation.

> This problem is solved in Java, which does have a static exception checking,


> and where therefore the exception specifications are in fact very useful, as
> it reports any exceptions not caught, at compile-time.
>

[stuff about java snipped]

My proposal discusses the way it is done in Java and how this is
different again from onlythrow. I raised this issue a while ago on
USENET and got lots of feedback from Java developers who do not like
the way it is done in Java. I believe I have addressed these concerns
which arise mainly from Java's view that exceptions should always be
subject to single level propagation only. With my proposal you can
still have multi-level propagation which is argued for quite strongly
in D&E and in a paper written by Koenig and Stroustrup.

Regards,

Andrew M.

Mary K. Kuhner

unread,
Nov 21, 2001, 2:21:09 PM11/21/01
to
In article <d1a33011.01111...@posting.google.com>,
apm <ap...@student.open.ac.uk> wrote:

>By using the word 'onlythrow' instead of 'throw', exception
>specifications are subject to static checking and single level
>propagation. Violations of an onlythrow list are a compilation error.

>[...] A compiler that implements onlythrow must ship with a


>standard C++ library that uses onlythrow rather than throw in its
>exception specifications.

Doesn't this make use of the STL containers very difficult?

Many operations in vector<T> cannot be onlythrow, because
they require use of T's copy constructor or operator=, and
those could throw anything. (I guess the vector could
do catch{...} and silently absorb all exceptions, but I don't
think that would be a good idea.)

This means that vectors cannot be used in any code that has
onlythrow() specs, even if the programmer knows that the type
T is, in fact, safe (for example, vector<int>).

If I had to do without vectors, or do without onlythrow, you
can bet I'd do without onlythrow.

Do you see any way to make vectors, or other template code,
useful with onlythrow? I think that's the point that has
killed static exception specs in the past.

Mary Kuhner mkku...@genetics.washington.edu

Brian McKeever

unread,
Nov 21, 2001, 2:23:10 PM11/21/01
to
"apm" <ap...@student.open.ac.uk> wrote in message
news:d1a33011.0111...@posting.google.com...

> > This problem is solved in Java, which does have a static exception
checking,
> > and where therefore the exception specifications are in fact very
useful, as
> > it reports any exceptions not caught, at compile-time.
> >
> [stuff about java snipped]
>
> My proposal discusses the way it is done in Java and how this is
> different again from onlythrow. I raised this issue a while ago on
> USENET and got lots of feedback from Java developers who do not like
> the way it is done in Java. I believe I have addressed these concerns
> which arise mainly from Java's view that exceptions should always be
> subject to single level propagation only. With my proposal you can
> still have multi-level propagation which is argued for quite strongly
> in D&E and in a paper written by Koenig and Stroustrup.

I don't want to turn this into a discussion/debate of Java's exception
declaration facility, but could you explain how it is different from your
proposal and why? I am mostly satisfied with Java's exception declaration,
and I think it would serve as a fine basis for such a feature of C++. Also,
what do you mean by the term "single level propagation"?

Brian

Terje Slettebø

unread,
Nov 21, 2001, 2:23:40 PM11/21/01
to
"apm" <ap...@student.open.ac.uk> wrote in message
news:d1a33011.0111...@posting.google.com...

From your first posting:

"apm" <ap...@student.open.ac.uk> wrote in message

news:d1a33011.01111...@posting.google.com...


>
> By using the word 'onlythrow' instead of 'throw', exception

> specifications are subject to static checking and single level

> propagation. Violations of an onlythrow list are a compilation error.

From your next last posting:

> I believe I have addressed these concerns
> which arise mainly from Java's view that exceptions should always be
> subject to single level propagation only. With my proposal you can
> still have multi-level propagation which is argued for quite strongly
> in D&E and in a paper written by Koenig and Stroustrup.

Do you here mean that with "onlythrow" you only have single level
propagation, like in Java, but it would also be possible, using the usual
throw-lists, to have multi-level propagation?

In other words, do you argue for an exception handling, that is like that in
Java (using "onlythrow"), but that this is in addition to the usual
throw-lists, so you can use either?

Finally, what does it mean that something is single level or multi level
propagation? :) I thought exceptions in Java could jump over multiple
stackframes, providing that each stackframe it passes, during stack
unwinding, acknowledges its existence, by having the appropriate
exception-specification? (Checked statically)


> I raised this issue a while ago on
> USENET and got lots of feedback from Java developers who do not like
> the way it is done in Java. I believe I have addressed these concerns
> which arise mainly from Java's view that exceptions should always be
> subject to single level propagation only.

If "onlythrow" is similar to the way it's done in Java, why do you argue
that this solves any problems with the Java way of doing it?

Or do you mean that, having it _in addition_ to throw-lists, is what solves
this?

I didn't say the way it's done in Java, would have to be the only way to
handle it, in C++. That would break existing code using throw-lists. Having
an additional specification, like "onlythrow", could be ok.


I hope you can clarify what you meant, in the above, because it left me a
little confused. It's like you said, "No, that way you propose is not good,"
and then you propose the same, yourself.


Regards,

Terje Sletteb, Norway

Jani Kajala

unread,
Nov 21, 2001, 4:36:46 PM11/21/01
to
"Pavel Kuznetsov" <su41vo...@sneakemail.com> wrote in message
news:9t5f7p$etfk$1...@ID-97366.news.dfncis.de...

> Since throw specification as is IMHO could be considered having quite
> limited utility, I'd prefer having throw specification to follow
> onlythrow semantics.

I'd also prefer this option. Divide-by-zero and similar exceptions are
always
programming errors and can be handled separately without introducing
inconsistency. C++ is already complicated enough without more keywords and I
believe nobody would miss the current C++ exception specification. I prefer
C++
over Java in many issues but my experiences from the Java exception specs
has
been very good, the specs help especially in larger project with multiple
programmers, by forcing to make it explicit that the function can throw some
exception. If the compiler doesn't help then it is next to impossible to
make
sure every function has correct thrown exceptions documented.


Regards,
Jani Kajala

"Pavel Kuznetsov" <su41vo...@sneakemail.com> wrote in message
news:9t5f7p$etfk$1...@ID-97366.news.dfncis.de...

apm

unread,
Nov 22, 2001, 5:45:04 AM11/22/01
to
"Jani Kajala" <ja...@REMOVETHIS.sumea.com> wrote in message news:<9tggb8$q2v$1...@news1.song.fi>...

> "Pavel Kuznetsov" <su41vo...@sneakemail.com> wrote in message
> news:9t5f7p$etfk$1...@ID-97366.news.dfncis.de...
> > Since throw specification as is IMHO could be considered having quite
> > limited utility, I'd prefer having throw specification to follow
> > onlythrow semantics.
>
> I'd also prefer this option. Divide-by-zero and similar exceptions are
> always programming errors and can be handled separately without introducing
> inconsistency.

I agree. Andrew Koenig raised this point and I thought long and hard
about it before coming to my conclusion. My answer is that if code
causes undefined behaviour at runtime due to the problems in
expression evaulation mentioned in the standard in chapter 5 clause 5,
then such a routine has had its preconditions violated. This has to
mean that all bets are off including any onlythrow that might have
been specified.

apm

unread,
Nov 22, 2001, 5:45:46 AM11/22/01
to
"Brian McKeever" <bmck...@laserfiche.com> wrote in message news:<9tetr8$2hi8$1...@madmax.keyway.net>...

> "apm" <ap...@student.open.ac.uk> wrote in message
> news:d1a33011.0111...@posting.google.com...
> > [stuff about java snipped]
> >
> > My proposal discusses the way it is done in Java and how this is
> > different again from onlythrow.
[more snipping...]

>
> I don't want to turn this into a discussion/debate of Java's exception
> declaration facility

Good. Let's not do that everyone *please*.

>, but could you explain how it is different from your
> proposal and why?

I did not want to make a long post. There are a lot of issues to
cover. I will put the full text of the proposal on my web site soon as
a PDF document. I will post the URL here when it is available. I have
already sent copies to a few people for review before I mentioned it
here.

> I am mostly satisfied with Java's exception declaration,
> and I think it would serve as a fine basis for such a feature of C++.

Many other people are too but opinion is still divided. I wanted to
come up with something that would be acceptable to the vast majority.

> Also, what do you mean by the term "single level propagation"?
>
> Brian

I refer you to the exception papaer written by Koenig and Stroustrup.
It is mentioned in D&E which also has a good section on why exception
handling and exception specifications are the way they are.

Regards,

Andrew M.

apm

unread,
Nov 22, 2001, 5:48:30 AM11/22/01
to
Terje Sletteb <tsle...@start.no> wrote in message news:<d8DK7.3901$Sa4.5...@news01.chello.no>...

> From your next last posting:
>
> > I believe I have addressed these concerns
> > which arise mainly from Java's view that exceptions should always be
> > subject to single level propagation only. With my proposal you can
> > still have multi-level propagation which is argued for quite strongly
> > in D&E and in a paper written by Koenig and Stroustrup.
>
> Do you here mean that with "onlythrow" you only have single level
> propagation, like in Java, but it would also be possible, using the usual
> throw-lists, to have multi-level propagation?

Yes, that's exactly what I mean :-)

>
> In other words, do you argue for an exception handling, that is like that in
> Java (using "onlythrow"), but that this is in addition to the usual
> throw-lists, so you can use either?

Very close. It certainly is an addition but there are differences.
These are discussed in detail in the full proposal which I did not
want to post here initially because it is quite long. It will be
available on the web as a PDF very soon.

>
> Finally, what does it mean that something is single level or multi level
> propagation? :)

This is explained in D&E.

I thought exceptions in Java could jump over multiple
> stackframes, providing that each stackframe it passes, during stack
> unwinding, acknowledges its existence, by having the appropriate
> exception-specification? (Checked statically)

Yes but it's still single level propagation according to D&E's use of
the term. See D&E.

> > I raised this issue a while ago on
> > USENET and got lots of feedback from Java developers who do not like
> > the way it is done in Java. I believe I have addressed these concerns
> > which arise mainly from Java's view that exceptions should always be
> > subject to single level propagation only.
>
> If "onlythrow" is similar to the way it's done in Java, why do you argue
> that this solves any problems with the Java way of doing it?

It is *similar* to java but not identical. There are a number of
differences.

>
> Or do you mean that, having it _in addition_ to throw-lists, is what solves
> this?

No. The addition rather than changing the way current exception
specifications work is to preserve compatibility with existing C++
code.

> I hope you can clarify what you meant, in the above, because it left me a
> little confused.

My writing has been known to do this :-)

> It's like you said, "No, that way you propose is not good,"
> and then you propose the same, yourself.

Not quite, but reviewing my post I can see how it might look like
that. One of the most important differences between onlythrow and the
java way is that with java just calling a routines that has an
exception specification requires that the caller also deals with it.
This is not true of onlythrow. This is because this aspect of java is
resented by alot of java programmers (although there are others that
*love* it). Quite a while ago I posted a similar proposal where I was
proposing that it work in JUST THE SAME WAY as java. What happened
then was that the java developers that don't like this aspect of java
gaves howls of protest. I later realised that the java way does not
quite fit in with the design by contract view of preconditions and
postconditions. This is because with DbC we may loosen the
preconditions (a class that requires less can certain be used with a
client that provides more) and we can tighten up the postconditions (a
class that provides stronger postconditions can certainly be used by a
client that expects less). This can be summarized by the slogan:

Require no more, promise no less.

The trouble with the java way (IMHO) is that it breaks the 'require no
more' bit. This is, I think, why many Java developers don't like it.

Regards,

Andrew M.

apm

unread,
Nov 22, 2001, 5:51:47 AM11/22/01
to
mkku...@kingman.genetics.washington.edu (Mary K. Kuhner) wrote in message news:<9t4q17$1bfa$1...@nntp6.u.washington.edu>...

> In article <d1a33011.01111...@posting.google.com>,
> apm <ap...@student.open.ac.uk> wrote:
>
> >By using the word 'onlythrow' instead of 'throw', exception
> >specifications are subject to static checking and single level
> >propagation. Violations of an onlythrow list are a compilation error.
> >[...] A compiler that implements onlythrow must ship with a
> >standard C++ library that uses onlythrow rather than throw in its
> >exception specifications.
>
> Doesn't this make use of the STL containers very difficult?

Well spotted :-)

> Do you see any way to make vectors, or other template code,
> useful with onlythrow? I think that's the point that has
> killed static exception specs in the past.
>
> Mary Kuhner mkku...@genetics.washington.edu

This is actually covered in my proposal doc. I mention Scott Meyers,
who says in one of his books that "exception specifications and
templates don't mix". I point out how true this is and say 'and even
more so with onlythrow'. One important point to note is that the
signatures in the standard have 'throw()' on the destructors of STL
classes. I discuss the implications that this has for onlythrow in my
document. I can see that I will have to post my document now as a
matter of urgency since I am starting to refer to it alot and no-one
can see it yet.

Regards,

Andrew M.

Terje Slettebø

unread,
Nov 22, 2001, 10:57:18 AM11/22/01
to
"apm" <ap...@student.open.ac.uk> wrote in message
news:d1a33011.01112...@posting.google.com...

> Terje Sletteb <tsle...@start.no> wrote in message
news:<d8DK7.3901$Sa4.5...@news01.chello.no>...
> > From your next last posting:
> >
> > In other words, do you argue for an exception handling, that is like
that in
> > Java (using "onlythrow"), but that this is in addition to the usual
> > throw-lists, so you can use either?
>
> Very close. It certainly is an addition but there are differences.
> These are discussed in detail in the full proposal which I did not
> want to post here initially because it is quite long. It will be
> available on the web as a PDF very soon.
>
> >
> > Finally, what does it mean that something is single level or multi
level
> > propagation? :)
>
> This is explained in D&E.

Ok. I have this one.

> Not quite, but reviewing my post I can see how it might look like
> that. One of the most important differences between onlythrow and the
> java way is that with java just calling a routines that has an
> exception specification requires that the caller also deals with it.
> This is not true of onlythrow. This is because this aspect of java is
> resented by alot of java programmers (although there are others that
> *love* it).

I tends to give "cascades" of exception specifications, if a function deep
down a call chain has an exception specificatin, then, unless this is caught
somewhere on the way up, it must be delared in each function on the way up,
as well. But after all, that is what static checking is about: It tells
which (if any) exceptions a function can throw, so clients of the class know
about it. It's part of the complete function signature.

> Quite a while ago I posted a similar proposal where I was
> proposing that it work in JUST THE SAME WAY as java. What happened
> then was that the java developers that don't like this aspect of java
> gaves howls of protest. I later realised that the java way does not
> quite fit in with the design by contract view of preconditions and
> postconditions. This is because with DbC we may loosen the
> preconditions (a class that requires less can certain be used with a
> client that provides more) and we can tighten up the postconditions (a
> class that provides stronger postconditions can certainly be used by a
> client that expects less). This can be summarized by the slogan:
>
> Require no more, promise no less.
>
> The trouble with the java way (IMHO) is that it breaks the 'require no
> more' bit. This is, I think, why many Java developers don't like it.

You said your proposal would be available on the Web, later. Still, could
you have given a concrete example of code using it, here? (Just the outline)

This might make it easier to understand how it's different from Java's
static checking.


Regards,

Terje Sletteb

tslettebo at chello dot no.

Francis Glassborow

unread,
Nov 22, 2001, 6:17:06 PM11/22/01
to
In article <MN7L7.4083$Sa4.5...@news01.chello.no>, Terje Slettebø
<clcppm...@this.is.invalid> writes

>I tends to give "cascades" of exception specifications, if a function deep
>down a call chain has an exception specificatin, then, unless this is caught
>somewhere on the way up, it must be delared in each function on the way up,
>as well.

Only if you elect to use exception specifications.

> But after all, that is what static checking is about: It tells
>which (if any) exceptions a function can throw, so clients of the class know
>about it. It's part of the complete function signature.

But the main issue is that exception specifications are not checked at
compile time (statically)

--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

James Kanze

unread,
Nov 23, 2001, 12:08:23 AM11/23/01
to
mkku...@kingman.genetics.washington.edu (Mary K. Kuhner) wrote in
message news:<9t4q17$1bfa$1...@nntp6.u.washington.edu>...

> >By using the word 'onlythrow' instead of 'throw', exception
> >specifications are subject to static checking and single level
> >propagation. Violations of an onlythrow list are a compilation
> >error. [...] A compiler that implements onlythrow must ship with
> >a standard C++ library that uses onlythrow rather than throw in
> >its exception specifications.

> Doesn't this make use of the STL containers very difficult?

It makes it in general difficult to write templates. In general, I'm
in favor of static checking of exceptions, but in order for it to work
in C++, it would be necessary to devise a syntax so that you could
declare that function X may throw anything that function Y may throw.
The declaration for std::vector might then start :

template< typename T >
class vector
{
public:
explicit vector< size_type n , T const& init = T() )
throw( from T::T( T const& ) ) ;
// ...
} ;

(except that I don't think that that is a very good syntax for it)

> Do you see any way to make vectors, or other template code, useful
> with onlythrow? I think that's the point that has killed static
> exception specs in the past.

I think what killed it was more the fact that it might, in some
particular cases, introduce extra unnecessary overhead. Something
along the lines of:

extern double sqrt( double ) throw ( illegal_argument ) ;

double
safeSqrt( double d ) throw()
{
return d > 0.0 ? sqrt( d ) : 0.0 ;
}

As written, with checked exceptions, this code would be illegal --
safeSqrt declares that it will never throw, but it does nothing about
the declared possible exception from sqrt. It does nothing because,
of course, it knows that because of previous checks, sqrt cannot throw
in this case.

That's the rationale. Of course, if none of the things we knew could
never happen never did, our software would crash a lot less often.

--
James Kanze mailto:ka...@gabi-soft.de
Beratung in objektorientierer Datenverarbeitung --
-- Conseils en informatique orientée objet
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany, Tél.: +49 (0)69 19 86 27

Terje Slettebø

unread,
Nov 23, 2001, 6:05:01 AM11/23/01
to
"Francis Glassborow" <francis.g...@ntlworld.com> wrote in message
news:lG5jEuAaYT$7E...@robinton.ntlworld.com...

> In article <MN7L7.4083$Sa4.5...@news01.chello.no>, Terje Sletteb
> <clcppm...@this.is.invalid> writes
> >I tends to give "cascades" of exception specifications, if a function
deep
> >down a call chain has an exception specificatin, then, unless this is
caught
> >somewhere on the way up, it must be delared in each function on the way
up,
> >as well.
>
> Only if you elect to use exception specifications.

Since when?

We're talking about Java, here. Exception specification there is mandatory
(except for unchecked exceptions, where it's voluntary).

> > But after all, that is what static checking is about: It tells
> >which (if any) exceptions a function can throw, so clients of the class
know
> >about it. It's part of the complete function signature.
>
> But the main issue is that exception specifications are not checked at
> compile time (statically)

In C++, yes. But I think you took my message for discussing exceptions
specifications, as they are in C++. If you look at the message I replied to,
you'll see that this was about Java.

In Java, they are checked statically.


Regards,

Terje Sletteb

tslettebo at chello dot no.

Early Ehlinger

unread,
Nov 23, 2001, 6:12:22 AM11/23/01
to
"Mary K. Kuhner" <mkku...@kingman.genetics.washington.edu> wrote

> apm <ap...@student.open.ac.uk> wrote:
> >By using the word 'onlythrow' instead of 'throw', exception
> >specifications are subject to static checking and single level
> >propagation. Violations of an onlythrow list are a compilation error.
> >[...] A compiler that implements onlythrow must ship with a
> >standard C++ library that uses onlythrow rather than throw in its
> >exception specifications.
>
> Doesn't this make use of the STL containers very difficult?
>
> Do you see any way to make vectors, or other template code,
> useful with onlythrow? I think that's the point that has
> killed static exception specs in the past.

hmmm.

template< ... >
class vector
{
void push_back( value_type const& el ) onlythrow( <value_type> ,
bad_alloc )
{ /* ... */ }
};

where onlythrow<> means that the compiler must generate the onlythrow list
based on the onlythrow specified by the members of value_type used by
push_back, if present, in addition to bad_alloc. If push_back uses anything
else and doesn't contain the exceptions thrown by them (say, a loggin
function), then push_back is broken. If value_type doesn't specify, then it
is safe to assume that value_type may throw anything and thus that push_back
may throw anything. So:

class foo
{
public:
foo( foo const& copy ); /* throws any exception, at will! */
foo( ) onlythrow(); /* throws no exceptions, guaranteed! */
};

class bar
{
public:
bar( bar const& copy ) onlythrow( junk ); /* throws junk only,
guaranteed! */
bar( ) onlythrow(); /* throws no exceptions, guaranteed! */
};

void f( ) onlythrow( bad_alloc , junk )
{
std::vector< foo > foos; /* ok vector::vector throws nothing */
std::vector< bar > bars; /* ok vector::vector throws nothing */

bar x; /* ok - bar::bar() throws nothing, doesn't violate f's onlythrow
list */

bars.push_back( x );
/* ok - push_back can throw
bad_alloc or junk - doesn't
violate f's onlythrow list */

foo y;
/* ok - foo::foo() throws
nothing, doesn't violate
f's onlythrow list */

foos.push_back( y );
/* error! push_back throws
any exception b/c of
foo::foo( foo const& )! */
}

This is just one possible solution to the template vs. static-throw-spec
quagmire.

-- Early Ehlinger

Francis Glassborow

unread,
Nov 23, 2001, 11:36:04 AM11/23/01
to
In article <NhiL7.4152$Sa4.5...@news01.chello.no>, Terje Slettebø
<clcppm...@this.is.invalid> writes

>"Francis Glassborow" <francis.g...@ntlworld.com> wrote in message
>news:lG5jEuAaYT$7E...@robinton.ntlworld.com...
> > In article <MN7L7.4083$Sa4.5...@news01.chello.no>, Terje Sletteb
> > <clcppm...@this.is.invalid> writes
> > >I tends to give "cascades" of exception specifications, if a function
>deep
> > >down a call chain has an exception specificatin, then, unless this is
>caught
> > >somewhere on the way up, it must be delared in each function on the way
>up,
> > >as well.
> >
> > Only if you elect to use exception specifications.
>
>Since when?
>
>We're talking about Java, here. Exception specification there is mandatory
>(except for unchecked exceptions, where it's voluntary).

You may have been, but that was by no means clear in what you wrote.
This is a C++ group and by default I think it is fair to assume that
statements are about C++ coding.

--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

apm

unread,
Nov 23, 2001, 12:49:16 PM11/23/01
to
"Early Ehlinger" <ear...@yahoo.com> wrote in message news:<x7kL7.54840$lV4.7...@e420r-atl1.usenetserver.com>...

> "Mary K. Kuhner" <mkku...@kingman.genetics.washington.edu> wrote
> > Doesn't this make use of the STL containers very difficult?
> hmmm.
[complicated stuff snipped]

> This is just one possible solution to the template vs. static-throw-spec
> quagmire.
>
> -- Early Ehlinger

There is another solution: the one proposed by Scott Meyers in
Effective C++ item 14 (I hope I got that right...). He says "exception
specifications and templates don't mix". Recent posts on this thread
support Meyer's argument, in my opinion. I think onlythrow does not
change things. The problem exists with both kinds of exception
specification. The solution is "don't do that then!". This is what I
say about the issue in the proposal document, to be issued RSN.

Regards,

Andrew M.

Terje Slettebø

unread,
Nov 23, 2001, 6:47:15 PM11/23/01
to
"Francis Glassborow" <francis.g...@ntlworld.com> wrote in message
news:3mYncaBfXj$7E...@robinton.ntlworld.com...

> In article <NhiL7.4152$Sa4.5...@news01.chello.no>, Terje Sletteb
> <clcppm...@this.is.invalid> writes
> >"Francis Glassborow" <francis.g...@ntlworld.com> wrote in message
> >news:lG5jEuAaYT$7E...@robinton.ntlworld.com...
> > > In article <MN7L7.4083$Sa4.5...@news01.chello.no>, Terje Sletteb
> > > <clcppm...@this.is.invalid> writes
> > > >I tends to give "cascades" of exception specifications, if a function
> >deep
> > > >down a call chain has an exception specificatin, then, unless this is
> >caught
> > > >somewhere on the way up, it must be delared in each function on the
way
> >up,
> > > >as well.
> > >
> > > Only if you elect to use exception specifications.
> >
> >Since when?
> >
> >We're talking about Java, here. Exception specification there is
mandatory
> >(except for unchecked exceptions, where it's voluntary).
>
> You may have been, but that was by no means clear in what you wrote.
> This is a C++ group and by default I think it is fair to assume that
> statements are about C++ coding.

I thought it would be fairly clear from what I said.

apm said:

>> Not quite, but reviewing my post I can see how it might look like
>> that. One of the most important differences between onlythrow and the
>> java way is that with java just calling a routines that has an
>> exception specification requires that the caller also deals with it.
>> This is not true of onlythrow. This is because this aspect of java is
>> resented by alot of java programmers (although there are others that
>> *love* it).

>I tends to give "cascades" of exception specifications, if a function deep


>down a call chain has an exception specificatin, then, unless this is
caught
>somewhere on the way up, it must be delared in each function on the way up,

>as well. But after all, that is what static checking is about: It tells


>which (if any) exceptions a function can throw, so clients of the class
know
>about it. It's part of the complete function signature.

apm talks about the way it's done in Java. I comment on this, and mention
that this is what static checking is all about.

C++ throw-specifications aren't statically checked (you won't get a
compile-time check for their validity).

Therefore, it should be clear that I was, indeed, talking about Java, which
was the last line I quoted, before the reply, too.


Regards,

Terje Sletteb

tslettebo at chello dot no.

apm

unread,
Nov 23, 2001, 6:51:46 PM11/23/01
to
ap...@student.open.ac.uk (apm) wrote in message news:<d1a33011.01111...@posting.google.com>...

> Here's a concise summary of my proposal for stricter exception
> specifications:
[snip]

> I have a longer document that describes the proposal in detail but I
> thought I would see what interest there is first.
>
Here it is:

http://www.andrewmarlow.co.uk/publications.html

Happy reading,

Francis Glassborow

unread,
Nov 23, 2001, 7:07:06 PM11/23/01
to
In article <d1a33011.0111...@posting.google.com>, apm
<ap...@student.open.ac.uk> writes

>There is another solution: the one proposed by Scott Meyers in
>Effective C++ item 14 (I hope I got that right...). He says "exception
>specifications and templates don't mix". Recent posts on this thread
>support Meyer's argument, in my opinion. I think onlythrow does not
>change things. The problem exists with both kinds of exception
>specification. The solution is "don't do that then!". This is what I
>say about the issue in the proposal document, to be issued RSN.

I think we need a fundamental rethink about exception specs. They need
to be statically enforced and we need to find a way to get them to work
with templates. Unless we can do both those things, I would strongly
favour removing them. Even the semantics of throw() can be provided by
alternative syntax (try { function definition } catch(...) { do whatever
you think appropriate }

--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Dennett

unread,
Nov 24, 2001, 6:28:19 AM11/24/01
to
Francis Glassborow wrote:

> In article <d1a33011.0111...@posting.google.com>, apm
> <ap...@student.open.ac.uk> writes
>
>>There is another solution: the one proposed by Scott Meyers in
>>Effective C++ item 14 (I hope I got that right...). He says "exception
>>specifications and templates don't mix". Recent posts on this thread
>>support Meyer's argument, in my opinion. I think onlythrow does not
>>change things. The problem exists with both kinds of exception
>>specification. The solution is "don't do that then!". This is what I
>>say about the issue in the proposal document, to be issued RSN.
>>
>
> I think we need a fundamental rethink about exception specs. They need
> to be statically enforced and we need to find a way to get them to work
> with templates.


How about specifying exceptions by showing which operations
are to be used?

export template <typename A> void function
throw (std::bad_alloc,
my_namespace::my_exception,
using {
A a; // default construction
a = a; // copy assignment
A copy(a); // copy construction
});

The keyword "using" in the above is redundant, I think, but
I lean towards some redundancy as it can make code more
readable for humans (and sometimes make parsing easier for
compilers too).

The intention here is clearly that the compiler should
deduce the exception specification as the union of those
of the various operations used in the "using" block.

This echoes "constraints through use" in D&E (15.4.2).

-- James Dennett

apm

unread,
Nov 25, 2001, 6:58:28 AM11/25/01
to
Francis Glassborow <francis.g...@ntlworld.com> wrote in message news:<wMkGWlBtfp$7E...@robinton.ntlworld.com>...

> I think we need a fundamental rethink about exception specs.

Francis,

I find myself in very close agreement with you. We do need a
fundamental rethink about exceptions. It may be more fundamental than
any of us thought. I am now asking a VERY basic question: Do the
exceptions that a function is capable of throwing comprise part of its
contract?

Looking at the relevant literature, such as the C++ standard and
Object oriented Software Construction by Betrand Meyer, it would appear
that the answer to the above question is 'no'. It was always my
presupposition that the answer was 'yes' and it is this that caused me
to want to enforce stronger checking at compile-time rather than runtime.

I believe that if the answer is 'yes' then they need to be statically
enforced but IMHO we do *not* need them to get to work with templates.
This is where you and I differ. Several people that have posted on
this subject so far seem to think that the problems of static checking
in the presence of templates are a real showstopper. I think Scott
Meyers describes the problems with this very well in More Effective
C++, item 14. I think that a good way to enforce static checking would
be to adopt the changes in my proposal document and we leave the
problem of "exception specifications and templates don't mix" as an
unsolved problem. In other languages that support Design by Contract
(DbC) I think this problem should be tackled, maybe using some form of
constrained genericity (which, unfortunately, C++ does not support).

I also believe that if the answer is 'no' then exception
specifications should be deprecated and that my proposal for stronger
consistency checking of exception specifications should be withdrawn.
Much as we would like, we ought not to withdraw the current exception
specification facility, since it would cause problems for existing code.
There is a problem described by Herb Sutter which I mention in my proposal.
It is to do with the fact that exceptions that propagate from a destructor
can cause runtime failures that cannot be guarded against. I am not sure what
to do about this since the withdrawal of my proposal would leave this as
an unsolved problem. If we had the onlythrow keyword as per my proposal then
the solution would be to add onlythrow() to destructor signatures.
But if the answer really is 'no' then we may just have to live with this.
Herb's problem is still an open issue with the ANSI committee.

So I think that what we need to do now is answer this fundamental
question. My perspective is that I favour more rigour including more
static checking in modern programming languages. I am very sympathetic
to the idea of DbC. I don't think it's appropriate to add it to C++
because then C++ would be a different language. However, DbC has some
very useful ideas that can be used in other languages. I point to the
addition of prototypes to C and their strict enforcement in C++ as
examples of the benefits that stricter checking can bring even in
languages that do not have full DbC. The problem is 'how far do we
go?'. Languages that stress formalism and rigour tend to constrain
programmers in ways that C and C++ programmers may find
unacceptable. But a little discipline is good for us all.
I remember people complaining when prototypes were added to C.

My tendency to prefer more rigour is what led me to believe that the
exceptions that a function is capable of throwing *do* comprise part of
its contract. But this raises another even more fundamental question:
what are the differences between using exceptions and error codes and
what part do both play in designing a contract offered by a routine?
I think this question needs to be examined in order that we can decide
what the purpose of an exception is. Originally one of main driving forces
in C++ was that it provided a means of informing callers that an error
had occured within a constructor. Prior to that, people would have an 'ok'
state variable and objects had to check it to see whether or not they had
been constructed successfully. Exceptions also provide a useful way to indicate
errors for other parts of C++ syntax that do not allow the use of conventional
error codes, for example square bracket operator overloading. Betrand Meyer has
a much simpler definition: an exception is what occurs when a contract is broken.
I am still thinking about this one. :-)

Regards,

Andrew M.

Early Ehlinger

unread,
Nov 25, 2001, 8:46:17 AM11/25/01
to
> There is another solution [...] "don't do that then!". This is what I

> say about the issue in the proposal document, to be issued RSN.
> Andrew M.

Don't do that!? If that's how onlythrow would work with templates, then
onlythrow is entirely useless.

My code, and I suspect others', is becoming more and more dependent on the
Standard Library with every line of new code. If I can't use onlythrow and
have it flow through templates in some (useful) manner, then I can't use
static onlythrow *at all*!

I want onlythrow, to be sure; it would make it easier to detect bugs at
compile time and ensure a more robust system in general. However, a
fundamental requirement, for me anyway, is that it plays well with
templates. This could mean that there must be a mechanism for including
onlythrow from other functions or any number of mechanisms.

Another poster suggested something to this effect:

template< class X , class V >
void find( X& x , V& v ) onlythrow
( exception_not_found
, using( X::begin() ) /* union onlythrow spec from X::begin */
, using( X::end() ) /* union onlythrow spec from X::end */
, using( X::iterator::operator++() ) /* union onlythrow spec from
X::iterator::operator++ */
, using( V ) /* union onlythrow from all visible members of V. (normally
public members, unless find<> is a friend of V) */
); /* any possible exceptions from X's members other than those listed
*MUST* be caught and translated to something existing in the onlythrow spec
*/

This would be perfectly usable and effective, IMHO. And I don't find it
particularly complicated, either.

-- Early Ehlinger

Early Ehlinger

unread,
Nov 25, 2001, 8:48:11 AM11/25/01
to
"James Kanze" <ka...@gabi-soft.de> wrote
> > Do you see any way to make vectors, or other template code, useful
> > with onlythrow? I think that's the point that has killed static
> > exception specs in the past.
> I think what killed it was more the fact that it might, in some
> particular cases, introduce extra unnecessary overhead. Something
> along the lines of:
>
> extern double sqrt( double ) throw ( illegal_argument ) ;
>
> double
> safeSqrt( double d ) throw()
> {
> return d > 0.0 ? sqrt( d ) : 0.0 ;
> }
>
> As written, with checked exceptions, this code would be illegal --
> safeSqrt declares that it will never throw, but it does nothing about
> the declared possible exception from sqrt. It does nothing because,
> of course, it knows that because of previous checks, sqrt cannot throw
> in this case.

Hmm. This does put a damper on static-checking of exception specifications
\:(. Perhaps a companion to onlythrow should be wont_throw:

extern double sqrt( double ) onlythrow ( illegal_argument );

double safeSqrt( double d ) onlythrow()
{
if ( d > 0.0 )
wont_throw /* tells compiler that code in block will not throw, regardless
of onlythrow specifications contained. */
{
return sqrt( d );
}
else
return 0.0;
}

I don't particularly like this syntax, of course. Perhaps something like
"try { code } wont_throw;"

In any event, I am still convinced that static checking of throw
specifications would be an incredibly valuable language feature, provided
that it (a) supports templates and (b) doesn't compile the code as James
wrote it above, even though his safeSqrt would never throw illegal_argument.

-- Early Ehlinger

apm

unread,
Nov 25, 2001, 8:51:34 AM11/25/01
to
ap...@student.open.ac.uk (apm) wrote in message
news:<d1a33011.01112...@posting.google.com>...

> ap...@student.open.ac.uk (apm) wrote in message
news:<d1a33011.01111...@posting.google.com>...
> > Here's a concise summary of my proposal for stricter exception
> > specifications:
> [snip]
> > I have a longer document that describes the proposal in detail but I
> > thought I would see what interest there is first.
> >
> Here it is:
>
> http://www.andrewmarlow.co.uk/publications.html
>

I know it's considered bad form to reply to your own post but what the
heck...
I have looked at all the feedback about my proposal and have had a
complete rethink. Here's what I've come up with but be warned, it's
quite long.....

Thoughts about exceptions and Design by Contract in C++

I find what Betrand Meyer says in OOSC(II) very helpful. Here it is,
paraphrased: Exceptions are what occur when a function breaks its
contract. A contract is broken when either the client or the supplier
fails to meet their obligations.

However, what is not made clear is what lengths a function ought to go
to in order to see if the contract is being broken. Such checks are
normally part of defensive programming which DbC eschews. Often it is
lack of defensive programming that leads to the classic examples of
arithmetic exception such as calculating the square root of a negative
number or dividing by zero.

My preference is to use defensive programming and DbC together, even
though Meyer says you shouldn't. I argue that in the defensive code
exceptions ought to be used to indicate violated preconditions or
violated postconditions. The trouble with this is that people often
ignore preconditions and with my approach this would lead to
exceptions that might propagate right to the outermost level before
the program was terminated. The lack of portable stack tracing
mechanisms in C++ makes this situation awkward to debug but it helps
to have an application-standard exception base class whose constructor
takes a filename and line number.

A frequently asked question is "should my openfile function throw an
exception if the file is not found?". The answer lies in whether the
caller needs to know. If the caller has checked file existence as a
precondition of openfile then he does not need to know, in which case
if the file really does not exist then a precondition has been
violated.

The suppliers obligations may include informing the caller of errors.
If so and an error occurs then the contract is not being broken and
an exception should not be thrown. In my experience this is typical
of errors that raise from system routines that interact with the
filesystem.

So what should we use exceptions for? Well, in an ideal world
contracts should not be broken. This seems to be the Eiffel approach
where defensive programming is shunned in favour of establishing
preconditions. The violation of a precondition does not lead to an
exception being thrown in production code. Instead it gives undefined
behaviour. If a function discovers that it will not be able to honour
its postconditions despite the preconditions having been met then IMO
it should raise an exception to indicate this. There is another
school of thought that says that when a contract is broken then
because it is a case of 'all bets are off', exceptions may not be
thrown but undefined behaviour may result instead. I think this is
too harsh and leads to terrible debugging problems.

So to sum up the above, I advocate that C++ exceptions are used in
functions
that try to offer a DbC interface and that they throw the exceptions
when either preconditions or postconditions are violated and that they
make
the necessary checks explicitly using defensive coding techniques to
avoid the function yielding undefined behaviour.

It follows from this that the exceptions such a function may throw
should not be a part of the contract. After all, the exceptions only
occur when all bets are off. Furthermore, should the internals of the
algorithm change, it is conceivable that there might be different
reasons why the contract could not be honoured. Including these
reasons into the contract itself makes such contracts subject to
change in ways that cannot be anticipated by the caller. To make these
part of the contract burdens the caller with unecessary information.
It also becomes harmful if the mechanism whereby the exceptions that
form part of the contract are strictly enforced by static checking of
exception specifications. It means that algorithmic changes that a
function
undergoes may cause functions that call it to fail to compile.
If it is *that* important for the caller to know what went wrong then
perhaps the routine ought to be a bit like the 'openfile' routine
mentioned earlier, which informs the caller of any error as part of
its postcondition. Informally, the postcondition for openfile may be
expressed as:

open the file OR don't open it and say why not

At the start of this thread I submitted a proposal for strong static
exception
specification consistency checks to be added to C++ via a new keyword,
onlythrow. The main objection seems to be that they cause problems in
templated code. However, I have now had a complete rethink and I have
an objection of my own (!!!). I am now of the opinion that exception
specifications should not exist at all. We cannot turn the clock
back, of course, so this boils down to saying that they should not be
used.

This leaves one question: what do we do about people who ask us 'what
exceptions is your function capable of throwing?'. I now have a simple
answer to this no matter what the code is. My answer is "Why
do you want to know what happens when the contract is broken? Can you
mend a broken contract?". In other words, I refuse to tell
them. There are parts of C++ that are already like this where the
standard says that certain constructs may, but are not required, to
throw exceptions. So the person that employs such a construct cannot
know when it will go wrong. Presumably these constructs are so general
purpose that the standard cannot afford to dictate that their
implementation be coded defensively. Some environments might not be
able to afford the runtime costs. The exceptions that are capable of
being
thrown when the contract is broken are to some extent dependent on the
implementation of the function, and these implementation details
should
be hidden by the contractual interface.

This change in my thinking would make the use of exceptions quite
rare, much rarer than what we find in Java, say. IMO Java often uses
exceptions where an error code would be better.

The turning point in my thinking has come from me considering things
more from a DbC view. Many people come to exception specifications as
a form of documentation aid (hmm, let's see what might go wrong with
this routine). This used to to be my view also. Matters came to a
head on a project where I used doxygen to automatically generate the
documentation. The project started to use exception specifications
because they automatically got documented. Then we hit the fact that
because they weren't statically checked their use actually made us
more prone to unexpected being called than we otherwise would have
been. This caused me to consider asking ANSI to provide a means of
strong static checking. When I mentioned it to Stroustrup he suggested
that I post the proposal to comp.lang.c++.moderated, hence the recent
thread. The feedback I have received has been most helpful.

Regards,

Francis Glassborow

unread,
Nov 25, 2001, 9:56:36 PM11/25/01
to
In article <d1a33011.01112...@posting.google.com>, apm
<ap...@student.open.ac.uk> writes

>Francis Glassborow <francis.g...@ntlworld.com> wrote in message
news:<wMkGWlBtfp$7E...@robinton.ntlworld.com>...
>> I think we need a fundamental rethink about exception specs.
>
>Francis,
>
>I find myself in very close agreement with you. We do need a
>fundamental rethink about exceptions. It may be more fundamental than
>any of us thought. I am now asking a VERY basic question: Do the
>exceptions that a function is capable of throwing comprise part of its
>contract?

To save bandwidth I have snipped most of your posting but my response is
in the context of it.

Exactly what is meant by 'contract' here? I can think of little more
fundamental to contracts than 'if you break this guarantee, I am going
to stop work.' And effectively that is what an exception specification
states so I think the answer to your question is 'yes'.

Now as to the interaction between templates and exception
specifications: How can the be separated? Example:
template<typename T>
void foo(T) {
// whatever
}

Now I cannot provide any ES for foo because in general I have no idea
what exceptions can be generated by the use of T so:

void bar(){
foo(char c);
}

cannot have an ES, i.e. it will throw anything. These days very many
functions make use of instances of templates, either types or functions
(just use std::string). Every one of those functions must have 'can
throw anything' or else fail static checking. Unless they include a
catch(...) they must also throw anything. Hence I conclude that for
static enforcement of exception specifications we must find a mechanism
to solve the template problem.

There is a possibility that if exception specifications became deducible
that we might manage something.


--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Dave Harris

unread,
Nov 26, 2001, 2:27:08 AM11/26/01
to
francis.g...@ntlworld.com (Francis Glassborow) wrote (abridged):

> I think we need a fundamental rethink about exception specs. They need
> to be statically enforced and we need to find a way to get them to work
> with templates. Unless we can do both those things, I would strongly
> favour removing them. Even the semantics of throw() can be provided by
> alternative syntax (try { function definition } catch(...) { do whatever
> you think appropriate }

I think the no-throw guarantee is the only exception specification that is
really useful. And of course it is crucial, for writing exception-safe
code, so it deserves support.

I would like it to be statically enforced, and wouldn't mind if it was
quite onerous. Eg if no-throw routines could not use unprotected division,
or the throwing version of operator new(), or C-routines that don't have
exceptions specifications, or whatever. No-throw is mostly used for
simple, safe routines like swap() where the restrictions are not a
problem.

I suspect we can get from here to there without language changes.
Implementations should be encouraged to optimise away overhead for
no-throw declarations, and to issue warnings if they can't do that. I
think that would cover it.

Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
bran...@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."

Terje Slettebø

unread,
Nov 26, 2001, 5:22:29 AM11/26/01
to
"apm" <ap...@student.open.ac.uk> wrote in message
news:d1a33011.01112...@posting.google.com...
> Francis Glassborow <francis.g...@ntlworld.com> wrote in message
news:<wMkGWlBtfp$7E...@robinton.ntlworld.com>...
> > I think we need a fundamental rethink about exception specs.
>
> Francis,
>
> I find myself in very close agreement with you. We do need a
> fundamental rethink about exceptions. It may be more fundamental than
> any of us thought. I am now asking a VERY basic question: Do the
> exceptions that a function is capable of throwing comprise part of its
> contract?

I think so.

In other words, the contract doesn't just specify what the preconditions
are, but also what happens if they are not met.

I find this much more satisfying, than the current throw-specification which
basically says: "Either you only throw these exceptions, or else..." :)

In other words, if it violates that, it calls unexpected(), which default
calls terminate().

It's also better than if violation of the contract gives rise to undefined
behaviour (or unknown exceptions), which, it appears, is the opinion of
those arguing for "no" to the stated question.


> Betrand Meyer has
> a much simpler definition: an exception is what occurs when a contract is
broken.
> I am still thinking about this one. :-)

I disagree with this one.

Yes, exceptions are thrown if the contract is broken. So far so good.

However, it should also be part of the contract, to specify what the
consequences are, if the contract is broken.

This is similar to ordinary contracts.


However, it's not that easy to statically check for this, if you want to
avoid the rippling effects of exception specifications, like it is in Java.

To take an example similar to the one in the proposal (except that both
functions use onlythrow, rather than one with onlythrow, and one with
throw).


double absSqrt(double x) onlythrow()
{
return num<0 ? sqrt(-x) : sqrt(x) // Ensures that precondition is met
}

double sqrt(double x) onlythrow(illegal_argument)
{
// Precondition: x>=0
//
// If precondition is violated, exception is thrown

if(x<0)
throw illegal_argument;

// Perform calculation
...
}

I think the problem here is that the programmer knows that the precondition
is met, in the call to sqrt(), thus no try-catch clause is needed in
absSqrt(), however, the compiler doesn't know this, and it could be very
hard for it to check it.

Therefore, performing static checking, yet avoiding the rippling effect of
the caller either having to use try-catch, or declare it in its onlythrow,
as well, could be hard.

This stems from the problem of the compiler ensuring that the precondition
is actually met, at compile time.

Comments?


Regards,

Terje Slettebo

tslettebo at chello dot no.

Terje Slettebø

unread,
Nov 26, 2001, 5:33:50 AM11/26/01
to
"apm" <ap...@student.open.ac.uk> wrote in message
news:d1a33011.01112...@posting.google.com...
> ap...@student.open.ac.uk (apm) wrote in message
> news:<d1a33011.01112...@posting.google.com>...
> > ap...@student.open.ac.uk (apm) wrote in message
> news:<d1a33011.01111...@posting.google.com>...
> > > Here's a concise summary of my proposal for stricter exception
> > > specifications:
> > [snip]
> > > I have a longer document that describes the proposal in detail but I
> > > thought I would see what interest there is first.

Just an addition to my last posting.

> It follows from this that the exceptions such a function may throw
> should not be a part of the contract. After all, the exceptions only
> occur when all bets are off.

If this is done, it begs the larger question: How do you deal with
exceptions that the function may throw, if you don't know which (if any)
exceptions it may throw (no matter if it's documented in
throw-specifications, or not)?

Wouldn't this make exceptions essentially useless?

After all, the point with exceptions and try-catch, is that you can handle
the exceptions you know of, and is capable of handling, and, if wanted,
passing the rest on.


Furthermore, the point is that a function e.g. handling a file (like
reading/writing it) may not be able to know what to do with an error
condition, so it can't just absorb it, in order to not throw exceptions.

That's why we have exceptions, so they can be propagated to a handler higher
up in the call-chain, that may have the necessary information to deal with
it.

This also keeps error-correcting code out of the routines generating it, so
the handling may vary independently.


In short, treating exceptions as undefined behaviour (or unknown exceptions,
so they can only be caught with "catch(..)"), as is suggested here, I find
unsatisfactory.


Regards,

Terje Sletteb

tslettebo at chello dot no.

Mary K. Kuhner

unread,
Nov 26, 2001, 5:35:17 AM11/26/01
to
The C++ construct static_cast allows the coder to ask for a conversion
that may not be safe, and tell the compiler to take her word for it.

Maybe something similar would help with the static-checked exception
specs; a kind of "cast" that says "This code shouldn't be allowed
because of contradictory exception specifications, but I want it to
compile anyway."

This could be put around, for example, a mathematical expression
which would throw on a zero argument, but has a check that prevents
it from executing on a zero argument.

It would be unsafe in the same way that static_cast is, but
at least it would be a clear red flag in the code--you wouldn't
do this by accident.

Mary Kuhner mkku...@genetics.washington.edu

Mary K. Kuhner

unread,
Nov 26, 2001, 10:52:54 AM11/26/01
to
In article <d1a33011.01112...@posting.google.com>,
apm <ap...@student.open.ac.uk> wrote:

>It follows from this that the exceptions such a function may throw
>should not be a part of the contract. After all, the exceptions only
>occur when all bets are off.

This seems to lose the other major use of exceptions--to allow
an error to move from the code that emits it to the code capable
of dealing with it, without requiring the intermediate code to
be aware of it.

There are two examples of this in my current project. In one
case, code deep in the bowels of a mathematical model may
detect that a certain proposed "rearrangement" cannot be completed
successfully. This doesn't represent a failure of pre-conditions,
just a rare combination of random values. The model throws
an exception, and six levels higher I catch it, note that the
rearrangement failed, and go on. It's very clean. The error-
code version is *not* very clean; each of those six levels must
check for an error code and propagate it, possibly from multiple
points within the routine.

In the other case (not yet coded, but it will be) when we run
out of memory, the exception is caught nearly at the highest
level, a little stored-up memory is freed, and the program
attempts to write out its results to date before dying. This
one is practically impossible with error codes--you'd have to
string error recovery code through almost every routine in
the program, with nightmarish results. (I've coded things
like this in C. Yuch.) In particular, you now need *two*
error codes propagating through the routines described above, one
to signal out-of-memory, one to signal model failure.

You could make do with jump statements, except that then the
destructors aren't called, so if you use RAII you make a horrible
mess.

I would hate to lose this use of exceptions. I don't feel it should
be deprecated.

Mary Kuhner mkku...@genetics.washington.edu

Artem Livshits

unread,
Nov 26, 2001, 11:00:00 AM11/26/01
to
"apm" <ap...@student.open.ac.uk> wrote in message
news:d1a33011.01112...@posting.google.com...
> ap...@student.open.ac.uk (apm) wrote in message
news:<d1a33011.01111...@posting.google.com>...
> > Here's a concise summary of my proposal for stricter exception
> > specifications:
> [snip]
> > I have a longer document that describes the proposal in detail but I
> > thought I would see what interest there is first.
> >
> Here it is:
>
> http://www.andrewmarlow.co.uk/publications.html
>

As far as I can see the proposed solution only works for single level which
makes it of limited use (I hope that the proposal doesn't suggest to use
multiple levels of single-level static checking because that defeats the
purpose of exceptions -- abstract code that doesn't need to know about error
handling from error handling).

I can think of 3 reasons why we need to know about what exception an
operation can throw:

1. To make sure we handle them all.
2. To find out if we can handle some of them.
3. To make sure an operation doesn't throw (nothrow garantee).

For #1 I could think of the following example:

void foo(const char *arg) onlythrow(char *)
{
if (!arg)
throw "You must enter your name!";

printf("Hello, %s!\n", arg);
}

int main(int argc, char *argv[]) onlythrow ()
{
try
{
foo(argv[1]);
}
catch (char *s)
{
printf("ERROR: %s\n", s);
return -1;
}

return 0;
}

The exceptions in this program are checked statically, which is nice, but
the program has one problem: in vast majority of real programs exceptions
have to be propagated on more then one level. Adding a feature that can be
useful only in small (really small) number of situations seems questionable
to me.

Multi-level static checking would be beneficial here without a doubt and
would work with temlpates as well (because templates aren't a separate
special case but rather a consequence of the more general rule that the
code that doesn't handle exceptions shouldn't care about exact types of
exceptions) but I don't think it's feasible to implement.

For #2 I could think of the following example:

class Resource
{
public:
void Open();
void Create();

class ErrorDoesntExist {};
};

void foo(Resource &r)
{
try
{
r.Open();
}
catch (Resource::ErrorDoesntExist &)
{
r.Create();
}
}

Obviously for this example 'onlythrow' is not appropriate at all as we don't
care what exceptions Open can 'onlythrow', all we care about is what
exception means that the resource doesn't exist so we could catch and handle
it.

#3 is the case where the proposal is really useful. Some code can't be
implemented correctly without relying on the fact that some operations
provide nothrow garantee and it would be nice to have static checking for
it. In addition to this it would be nice to have some construction that says
(and statically checks) that some operations don't throw exceptions, e.g:

template<class T>
Stack<T>& Stack<T>::operator=( const Stack<T>& other )
{
if( this != &other )
{
T* v_new = NewCopy( other.v_, other.vsize_, other.vsize_ );
// if we got here, the allocation and copy were okay

nothrow // hypotetical nothrow block specifier
{
delete[] v_;
// note that this cannot throw, since T dtors cannot
// throw and ::operator delete[] is declared as throw()

v_ = v_new;
vsize_ = other.vsize_;
vused_ = other.vused_;
}
}

return *this; // safe, no copy involved
}

(the example is taken from GotW #8 http://www.gotw.ca/gotw/008.htm)

Currently the best we can do is to have some comments that say that we rely
upon that certain operations (like assignments of built-in types) never
throw but if the code is changed later and we use a class for vsize_ instead
of a built-in type which has a throwing assignment operator the compiler
won't help us (and even in run-time we'll get a hard-to-reproduce bug).

(This is not a proposal, just brain-storming the problem :)

So in summary, I think that static checking of exception specifications
should be either multi-level (almost impossible to implement) or should
check only for nothrow garantee.


Artem Livshits
Brainbench MVP for C++
http://www.brainbench.com

Francis Glassborow

unread,
Nov 26, 2001, 11:12:38 AM11/26/01
to
In article <9trk4p$1dgq$1...@nntp6.u.washington.edu>, Mary K. Kuhner
<mkku...@kingman.genetics.washington.edu> writes

>Maybe something similar would help with the static-checked exception
>specs; a kind of "cast" that says "This code shouldn't be allowed
>because of contradictory exception specifications, but I want it to
>compile anyway."

I suspect that for preservation of legacy code we would have to go the
other way and instruct the compiler that it must enforce exception
specifications statically.


--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

apm

unread,
Nov 26, 2001, 11:13:07 AM11/26/01
to
Francis Glassborow <francis.g...@ntlworld.com> wrote in message
news:<56+k7$B4QPA...@robinton.ntlworld.com>...

> Exactly what is meant by 'contract' here? I can think of little more
> fundamental to contracts than 'if you break this guarantee, I am going
> to stop work.' And effectively that is what an exception specification
> states so I think the answer to your question is 'yes'.

But IMO an ES does more than just say the contract has been broken. It
provides reasons why and IMO these should not form part of the
contract because the reasons are associated with the implementation,
not the interface. The contract should just be concerned with the
interface. If people really need to know the reason then perhaps it
would be more appropriate (for certain functions) to return an error
code. Then the contract would have a postcondition of:

do the work OR (don't and say why not)

Some functions cannot have a postcondition of the form above without
severely affecting the usability of the interface, for example the
sqrt function. sqrt has the precondition that the argument must be
non-negative. An alternative interface that allowed the caller to see
if he had supplied a bad argument would probably never be used.

However, for routines that can have such a postcondition then they
should if it is potentially useful for the caller, otherwise
pre/post-condition violation should result in an exception that the
caller will probably not deal with there-and-then. We need to provide
enough information when the exception is thrown so that they can do
some sort of recovery, but IMO this information should be minimal.

Regards,

Andrew M.

apm

unread,
Nov 26, 2001, 11:13:35 AM11/26/01
to
bran...@cix.co.uk (Dave Harris) wrote in message
news:<memo.20011125...@brangdon.madasafish.com>...

> francis.g...@ntlworld.com (Francis Glassborow) wrote (abridged):
> > I think we need a fundamental rethink about exception specs. They need
> > to be statically enforced and we need to find a way to get them to work
> > with templates. Unless we can do both those things, I would strongly
> > favour removing them. Even the semantics of throw() can be provided by
> > alternative syntax (try { function definition } catch(...) { do whatever
> > you think appropriate }
>
> I think the no-throw guarantee is the only exception specification that is
> really useful.

Now that I have done a shamless U-turn I will go further and say that
the no-throw guarantee is only useful for destructors, and even this
is just to fix up the fact that C++ allows exceptions to propagate
beyond dtors by default.

> And of course it is crucial, for writing exception-safe
> code, so it deserves support.

Maybe this is something I have missed. Would you please give an
example ?

Regards,

Andrew M.

apm

unread,
Nov 26, 2001, 2:45:14 PM11/26/01
to
mkku...@kingman.genetics.washington.edu (Mary K. Kuhner) wrote in message news:<9trk4p$1dgq$1...@nntp6.u.washington.edu>...

> The C++ construct static_cast allows the coder to ask for a conversion
> that may not be safe, and tell the compiler to take her word for it.
>
> Maybe something similar would help with the static-checked exception
> specs; a kind of "cast" that says "This code shouldn't be allowed
> because of contradictory exception specifications, but I want it to
> compile anyway."

But isn't this what we have already with ES? Little or no checking
then unexpected() if it turns out that the ES is violated.

-apm

Francis Glassborow

unread,
Nov 26, 2001, 4:58:34 PM11/26/01
to
In article <9ts8al$2r54$1...@nntp6.u.washington.edu>, Mary K. Kuhner
<mkku...@kingman.genetics.washington.edu> writes

>I would hate to lose this use of exceptions. I don't feel it should
>be deprecated.

I do not think you should have any fears on this score. Exceptions are a
powerful and valuable tool in C++. The problem is not with them but with
Exception Specifications which seem to be flawed.


--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

apm

unread,
Nov 26, 2001, 4:59:58 PM11/26/01
to
Terje Slettebø <clcppm...@this.is.invalid> wrote in message news:<oHaM7.4423$Sa4.6...@news01.chello.no>...

> In other words, the contract doesn't just specify what the preconditions
> are, but also what happens if they are not met.
>
> I find this much more satisfying, than the current throw-specification which
> basically says: "Either you only throw these exceptions, or else..." :)
> In other words, if it violates that, it calls unexpected(), which default
> calls terminate().

Although I am no longer asking for C++ to offer strong static
checking, I do not like the way that a violated ES calls unexpected.
But this can be dealt with by just not using ESs except on dtors. The
trouble with making an ES part of the contract is that you end up with
weak contracts because they are full of weasel-word get-out clauses.
:-)

> It's also better than if violation of the contract gives rise to undefined
> behaviour (or unknown exceptions),

Agreed. Undefined behaviour is awful. This is why I prefer defensive
coding combined with DbC.

> which, it appears, is the opinion of
> those arguing for "no" to the stated question.

No, not me. My answer to the question 'does it form part of the
contract' is 'no' but I think when the contract is broken exceptions
are thrown and they are documented. This is better than undefined
behaviour.

> Yes, exceptions are thrown if the contract is broken. So far so good.
> However, it should also be part of the contract, to specify what the
> consequences are, if the contract is broken.
> This is similar to ordinary contracts.

But taking the analogy a bit further, that makes an ES like penalty
clauses in a real-world contract. But what do you do when a contract
is broken and the offending party does not honour the penalty clause?
This is the problem with C++ ESs that I originally tried to address by
having stronger static checking. I wanted to make this situation
impossible for functions that used onlythrow. I agree that it is not
easy to get a compiler to check for this but I don't think it's
impossible. I would want penalty clauses in a real world contract and
I would consider them to be a part of the contract. But I don't think
the same thing applies in C++.

[example of why it is difficult to check snipped]

> Terje Slettebo
>
> tslettebo at chello dot no.

Thanks for the feedback. This is just the kind of debate I wanted to
get going. When I made my decision that an ES does not form part of
the DbC I searched the Eiffel conferences to see if it had been
discussed there. No such luck. There is more material in this
conference but still not a lot. I hope that people in both camps can
argue their view so that the associated issues will come out.

Regards,

Andrew M.

apm

unread,
Nov 26, 2001, 5:01:36 PM11/26/01
to
Terje Slettebø <clcppm...@this.is.invalid> wrote in message news:<3scM7.4439$Sa4.6...@news01.chello.no>...

> "apm" <ap...@student.open.ac.uk> wrote in message
> > It follows from this that the exceptions such a function may throw
> > should not be a part of the contract. After all, the exceptions only
> > occur when all bets are off.
>
> If this is done, it begs the larger question: How do you deal with
> exceptions that the function may throw, if you don't know which (if any)
> exceptions it may throw (no matter if it's documented in
> throw-specifications, or not)?

By-and-large I would not expect you to. After all if it was *that*
important to know then it ought to be part of the contract. If it
cannot be part of the contract, like with constructors or overloaded
[] operators, say, then the exceptions that might be thrown should be
documented. This is the approach taken by the C++ standard. Where an
app really needs to know more about the exception (and there are cases
sometimes) then I would manage this using inheritance. The whole
project would have a single base class for exceptions and more
specific exceptions would inherit from this. This enables anyone
interested in the derived type to catch it by derived type. Again, all
this would have to be documented rather than using exception
specifications.

Note that according to the standard in section 17.4.4.8 clause 1, an
implementation may 'strengthen' the ES for a function that is in the
C++ Standard Library by removing listed exceptions. I believe that
this supports the view the an ES is not to be viewed as part of the
contract.

>
> Wouldn't this make exceptions essentially useless?

It means that the exceptions that a function might throw have to be
documented.

>
> After all, the point with exceptions and try-catch, is that you can handle
> the exceptions you know of, and is capable of handling, and, if wanted,
> passing the rest on.

And you would still know them if they were documented.

> Furthermore, the point is that a function e.g. handling a file (like
> reading/writing it) may not be able to know what to do with an error
> condition, so it can't just absorb it, in order to not throw exceptions.

I have already discussed functions like openfile, readfile etc. IMO
these should not use exceptions to inform callers about filesystem
errors.

> That's why we have exceptions, so they can be propagated to a handler higher
> up in the call-chain, that may have the necessary information to deal with
> it.

This necessary information is usually acquired as a result of a higher
level view of things that knows whether or not failure of the called
upon routines can be tolerated. Code that needs to know in *detail*
usually traps the error much earlier in the form of an error code.

> This also keeps error-correcting code out of the routines generating it, so
> the handling may vary independently.
>
> In short, treating exceptions as undefined behaviour (or unknown exceptions,
> so they can only be caught with "catch(..)"), as is suggested here, I find
> unsatisfactory.

You probably won't get along with myself or Betrand Meyer then :-)
Only joking....

> Regards,
>
> Terje Sletteb

Thanks for the feedback,

apm

Mary K. Kuhner

unread,
Nov 26, 2001, 8:12:16 PM11/26/01
to
In article <d1a33011.0111...@posting.google.com>,

apm <ap...@student.open.ac.uk> wrote:
>mkku...@kingman.genetics.washington.edu (Mary K. Kuhner) wrote in message news:<9trk4p$1dgq$1...@nntp6.u.washington.edu>...
>> The C++ construct static_cast allows the coder to ask for a conversion
>> that may not be safe, and tell the compiler to take her word for it.

>> Maybe something similar would help with the static-checked exception
>> specs; a kind of "cast" that says "This code shouldn't be allowed
>> because of contradictory exception specifications, but I want it to
>> compile anyway."

>But isn't this what we have already with ES? Little or no checking
>then unexpected() if it turns out that the ES is violated.

I was trying to say that if static checking were to be implemented,
you could get rid of some of its drawbacks (specifically, the function
that looks as though it can throw, but the programmer knows it
can't) with a "cast-like" syntax.

It's like the difference between an untyped language (where the type
of a variable is never checked) and a typed language with casts (where
it is normally checked, but you can force a "forbidden" operation if
you want).

Mary Kuhner mkku...@genetics.washington.edu
(who learned OO in a totally untyped language, and once added a
dictionary word and a chair together....)

Terje Slettebø

unread,
Nov 26, 2001, 8:18:56 PM11/26/01
to
"apm" <ap...@student.open.ac.uk> wrote in message
news:d1a33011.01112...@posting.google.com...
> Terje Sletteb <clcppm...@this.is.invalid> wrote in message

news:<oHaM7.4423$Sa4.6...@news01.chello.no>...
> > In other words, the contract doesn't just specify what the preconditions
> > are, but also what happens if they are not met.
> >
> > I find this much more satisfying, than the current throw-specification
which
> > basically says: "Either you only throw these exceptions, or else..." :)
> > In other words, if it violates that, it calls unexpected(), which
default
> > calls terminate().
>
> Although I am no longer asking for C++ to offer strong static
> checking, I do not like the way that a violated ES calls unexpected.
> But this can be dealt with by just not using ESs except on dtors. The
> trouble with making an ES part of the contract is that you end up with
> weak contracts because they are full of weasel-word get-out clauses.
> :-)

On the contrary.

In a way, you arguing against yourself, here. :)

You suggest having specified exceptions (documented exceptions, they don't
need to be documented in the program code as throw-clauses). These
documented exceptions constitute the "What happens if the contract is
broken"-part.

Like I mention below, here, such specification may be considered part of the
contract, no matter if it's expressed in the code, or not.

So we really agree.

I can't understand why you think documented exceptions would make the
contract weaker (in that case, you're arguing for a weaker contract? :) ).
Like I said, on the contrary.

To take an example from ordinary contracts.

If you don't have anything to back a contract up, something that enforces
it, tells about the consequences of breaking it, either implicitely, in the
law, or explicitely stated, in the contract, _then_ you'd probably have a
weak contract, because there might be no consequences of breaking it. At
least, any consequences would be unknown.

However, with documented exceptions, the consequences are made perfectly
clear and unambiguous, so there's no doubt what the consequences are. Now
_that_ is a strong contract. :)

In invite you to clarify your view, though.

There may be just a misunderstanding, since we seem to agree, otherwise.


> > It's also better than if violation of the contract gives rise to
undefined
> > behaviour (or unknown exceptions),
>
> Agreed. Undefined behaviour is awful. This is why I prefer defensive
> coding combined with DbC.
>
> > which, it appears, is the opinion of
> > those arguing for "no" to the stated question.
>
> No, not me. My answer to the question 'does it form part of the
> contract' is 'no' but I think when the contract is broken exceptions
> are thrown and they are documented. This is better than undefined
> behaviour.

Then this is the same I meant. It's just different ways of saying it.

I suggested that exceptions are thrown when the contract is broken, and that
the exceptions that can be thrown, are documented (not unspecified). I
called this as part of the contract. Or, rather, a meta-part of the
contract, in a way, which deals with what happens when the contract is
broken. Both the contract, and the exception specifications, could be
considered part of the full contract.

So it's just really different ways of saying it. It's about having specified
exceptions, no matter what you call it.

So as mentioned, we agree, here.


> > Yes, exceptions are thrown if the contract is broken. So far so good.
> > However, it should also be part of the contract, to specify what the
> > consequences are, if the contract is broken.
> > This is similar to ordinary contracts.
>
> But taking the analogy a bit further, that makes an ES like penalty
> clauses in a real-world contract. But what do you do when a contract
> is broken and the offending party does not honour the penalty clause?
> This is the problem with C++ ESs that I originally tried to address by
> having stronger static checking. I wanted to make this situation
> impossible for functions that used onlythrow.

I agree with you, as mentioned earlier, that the ES in C++, now, aren't that
much use, since they are only checked at run-time, and then it's really too
late to do anything about it.


Regards,

Terje Slettebo

Early Ehlinger

unread,
Nov 27, 2001, 4:26:46 AM11/27/01
to
"Francis Glassborow" <francis.g...@ntlworld.com> wrote

> <mkku...@kingman.genetics.washington.edu> writes
> >Maybe something similar would help with the static-checked exception
> >specs; a kind of "cast" that says "This code shouldn't be allowed
> >because of contradictory exception specifications, but I want it to
> >compile anyway."
>
> I suspect that for preservation of legacy code we would have to go the
> other way and instruct the compiler that it must enforce exception
> specifications statically.

Isn't that the point of this thread (i.e., add onlythrow so as not to
break throw() )?

-- Early Ehlinger

Bob Bell

unread,
Nov 27, 2001, 12:34:24 PM11/27/01
to
> ... If it

> cannot be part of the contract, like with constructors or overloaded
> [] operators...

Not sure why you say this. Why can't an exception be part of the
contract with a constructor? It seems to me that since throwing an
exception is the only reasonable way for a constructor to report an
error, exceptions fit quite nicely into the contract that a
constructor can offer. For example, Foo::Foo() might never throw,
Foo::Foo(int) might throw a Bar, and Foo::Foo(char*) might throw a
Baz.

Bob

Bob Bell

unread,
Nov 27, 2001, 12:35:15 PM11/27/01
to
> But IMO an ES does more than just say the contract has been broken. It
> provides reasons why and IMO these should not form part of the
> contract because the reasons are associated with the implementation,
> not the interface. The contract should just be concerned with the
> interface. If people really need to know the reason then perhaps it
> would be more appropriate (for certain functions) to return an error
> code. Then the contract would have a postcondition of:
>
> do the work OR (don't and say why not)

This kind of postcondition is independent of the mechanism used to say
"why not." It can be an error code, a thrown exception, or any other
viable error-reporting mechanism. Arbitrarily deciding that exceptions
are a special error-reporting mechanism that somehow don't fit with
preconditions, postconditions and design-by-contract seems a little
specious to me.

Bob

apm

unread,
Nov 27, 2001, 12:37:12 PM11/27/01
to
Terje Slettebø <clcppm...@this.is.invalid> wrote in message
news:<BvzM7.4546$Sa4.6...@news01.chello.no>...

> "apm" <ap...@student.open.ac.uk> wrote in message
> news:d1a33011.01112...@posting.google.com...
> > Although I am no longer asking for C++ to offer strong static
> > checking, I do not like the way that a violated ES calls unexpected.
> > But this can be dealt with by just not using ESs except on dtors. The
> > trouble with making an ES part of the contract is that you end up with
> > weak contracts because they are full of weasel-word get-out clauses.
> > :-)
>
> On the contrary.
>
> In a way, you arguing against yourself, here. :)

I think that it was wrong of me to use the phrase 'weak contract'
because that means different thinks to different people. In fact it
has given the wrong impression which is my fault. I meant to say that
a contract is better if it concentrates on the job to be done rather
than what will happen if the job is NOT done. To do otherwise raises
the importance of exceptions to a level I am not happy with. For code
that really wants to know why the contract could not be honoured error
codes would probably be a better way.

I am not saying 'prefer error codes to exceptions'. I think that both
have a part to play in program design. I am saying that which you
choose depends on how important it is for the caller to know what went
wrong. If it is really important and it is just as likely the call
will fail a suceed, then I propose we have a contract of the form:

do the work OR (don't and say why not via an error code)

If on the other hand we have a contract where it is anticipated that
the contract will be honoured 99% of the time and that failure
indicates something like a programming bug or serious and RARE
mis-configuration, then exceptions should be used. I would not make
them part of the contract because that would mean that the caller
needs to know so badly that an error code approach would be better for
the caller.

> You suggest having specified exceptions (documented exceptions, they don't
> need to be documented in the program code as throw-clauses).

Ah but they do. This was a late-breaking discovery of mine by reading
the std. See section 17.4.4.8 clause 1.

> These documented exceptions constitute the "What happens if the contract is
> broken"-part.
>
> Like I mention below, here, such specification may be considered part of the
> contract, no matter if it's expressed in the code, or not.

This is the great debate now. I think that what we do with ES depends
on the answer to this question. My original proposal was because I
assumed that the above statement was true. I have now changed my mind.
But I welcome the debate because it is not an easy question and the
debate helps us all become aware of the issues. This thread is
starting to get rather large now so I would like to shift it to a new
thread that deals just with this question. I think we should put the
proposal to one side for now, especially as it might get bogged down
with the difficulties associated with ES and templates.

>
> So we really agree.

I don't think we do. It seems to me that you agree with what I thought
originally, that exceptions do comprise part of the contract. However,
I no longer think this. IMO the need for static checking hinges on
this.

>
> I can't understand why you think documented exceptions would make the
> contract weaker (in that case, you're arguing for a weaker contract? :) ).
> Like I said, on the contrary.

I wish I had never said this now. It is very misleading. I cocked it
up. Sorry. When I wrote that I was thinking that a weak contract was
one in which people wouldn't feel keen to sign up to because it
contained so many weasel-words that no-one would feel that it had high
chances of being honoured.

Of course some people DO like to sign such contracts because they are
so afraid of what will happen if the job is NOT done that they want to
cover all bases without lots of wrangling in court. However when I see
such a contract it makes me think the the other party is very worried
about what will happen if he fails to meet his part of the deal. I
then say to myself "Why is he this worried? Does he think he might not
be able to do it after all?". In real life this can be useful but I
think it is not so useful in programming unless the failure scenarios
are just as likely as the success scenarios. When this is the case I
think it is better to have a contract that says:

do the work OR (don't and say why not via an error code)

> However, with documented exceptions, the consequences are made perfectly
> clear and unambiguous, so there's no doubt what the consequences are. Now
> _that_ is a strong contract. :)

Yes. I should not have used the phrase 'weak contract'.

>
> In invite you to clarify your view, though.
>
> There may be just a misunderstanding, since we seem to agree, otherwise.

I think this is just a misunderstanding because I used the phrase
'weak contract' to refer to a contract that contains lots of
weasel-words. I shouldn't have done that. I can see now that some
people would think that this makes it a strong contract because it
covers all bases. Contracts like this are useful in the real world.
However, such a *programming* contract would make me think that the
other party was too concerned with things going wrong.

> I suggested that exceptions are thrown when the contract is broken, and that
> the exceptions that can be thrown, are documented (not unspecified). I
> called this as part of the contract. Or, rather, a meta-part of the
> contract, in a way, which deals with what happens when the contract is
> broken. Both the contract, and the exception specifications, could be
> considered part of the full contract.

At the risk of repeating myself, this is what I used to think when I
made the proposal but not any more. We both agree that exceptions are
what happens when the contract is broken but I am saying that this is
so exceptional that you would not try to cover all bases.

> > > Yes, exceptions are thrown if the contract is broken. So far so good.
> > > However, it should also be part of the contract, to specify what the
> > > consequences are, if the contract is broken.
> > > This is similar to ordinary contracts.

Yes it is but this is where real world contracts and programming
contracts differ. Real people are concerned with what happens if the
other party cannot meet its obligations because that is always a
possibility. But in programming I believe it should be so rare that
99% of the time the coder should not worry about it. Yes, provide a
means of catching the exception for those that do care but do not
expect it to be caught very often (except in main of course).

> I agree with you, as mentioned earlier, that the ES in C++, now, aren't that
> much use, since they are only checked at run-time, and then it's really too
> late to do anything about it.

When I thought that an ES was part of the contract I thought that C++
should make it more contractual by strong static checking. I still
think that static checking is better than runtime checking and that it
makes contracts that people have more confidence in but I no longer
think that the ES is part of the contract.

> Regards,
>
> Terje Slettebo

-apm

apm

unread,
Nov 27, 2001, 12:37:35 PM11/27/01
to
"Artem Livshits" <a_e_li...@yahoo.com> wrote in message
news:<9tsjn6$rj2$1...@newsreader.mailgate.org>...

> "apm" <ap...@student.open.ac.uk> wrote in message
> > Here it is:
> > http://www.andrewmarlow.co.uk/publications.html
>
> As far as I can see the proposed solution only works for single level

Yes that's right. It is intentional. The proposal goes into some
detail to explain the difference between single-level and multi-level
propgation and refers the reader to discussion in D&E.

Please note that the debate has shifted now. It is no longer about the
ES; it is now "does the ES form part of the contract?". My original
proposal assumed the answer was 'yes' but I have now changed my mind.
This effectively obsoletes the proposal.

-apm

Richard Smith

unread,
Nov 27, 2001, 6:04:32 PM11/27/01
to

"Early Ehlinger" <ear...@yahoo.com> wrote in message
news:dh_L7.18637$py4.11...@news2.nash1.tn.home.com...
> "James Kanze" <ka...@gabi-soft.de> wrote

> >
> > extern double sqrt( double ) throw ( illegal_argument ) ;
> >
> > double
> > safeSqrt( double d ) throw()
> > {
> > return d > 0.0 ? sqrt( d ) : 0.0 ;
> > }
> >
> > As written, with checked exceptions, this code would be illegal --
> > safeSqrt declares that it will never throw, but it does nothing about
> > the declared possible exception from sqrt. It does nothing because,
> > of course, it knows that because of previous checks, sqrt cannot throw
> > in this case.
>
> Hmm. This does put a damper on static-checking of exception
specifications
> \:(. Perhaps a companion to onlythrow should be wont_throw:
>
> extern double sqrt( double ) onlythrow ( illegal_argument );
>
> double safeSqrt( double d ) onlythrow()
> {
> if ( d > 0.0 )
> wont_throw /* tells compiler that code in block will not throw,
regardless
> of onlythrow specifications contained. */
> {
> return sqrt( d );
> }
> else
> return 0.0;
> }
>
> I don't particularly like this syntax, of course. Perhaps something like
> "try { code } wont_throw;"

Well... that can be done in the existing language:

#define wont_throw catch(...) { std::terminate(); }

... although it does mean the compiler has to generate code for the catch
statement rather than just ignoring the possibility that { code } might
throw an exception.

--
Richard Smith

Terje Slettebø

unread,
Nov 27, 2001, 6:31:18 PM11/27/01
to
"apm" <ap...@student.open.ac.uk> wrote in message
news:d1a33011.01112...@posting.google.com...
> Terje Slettebø <clcppm...@this.is.invalid> wrote in message
> news:<BvzM7.4546$Sa4.6...@news01.chello.no>...
> > "apm" <ap...@student.open.ac.uk> wrote in message
> > news:d1a33011.01112...@posting.google.com...
> > > Although I am no longer asking for C++ to offer strong static
> > > checking, I do not like the way that a violated ES calls unexpected.
> > > But this can be dealt with by just not using ESs except on dtors. The
> > > trouble with making an ES part of the contract is that you end up
with
> > > weak contracts because they are full of weasel-word get-out clauses.
> > > :-)
> >
> > On the contrary.
> >
> > In a way, you arguing against yourself, here. :)
>
> I think that it was wrong of me to use the phrase 'weak contract'
> because that means different thinks to different people. In fact it
> has given the wrong impression which is my fault. I meant to say that
> a contract is better if it concentrates on the job to be done rather
> than what will happen if the job is NOT done.

Ok. Then I understand what you meant.

> To do otherwise raises
> the importance of exceptions to a level I am not happy with. For code
> that really wants to know why the contract could not be honoured error
> codes would probably be a better way.

I'm very much against error codes for error conditions (cases where you
would use exceptions, otherwise). The reason is that the caller may, or may
not, check the error code.

If the error code isn't checked, the error goes undetected, possibly
chrashing an unrelated part of the program, or maybe causing the program to
fail in subtle ways, which is perhaps not detected.

It's the lack of checking for error codes, that is the reason for much of
today's buggy software (for example when Windows runs out of GDI-objects,
and windows fail to open, but no error is given. A clear indication that
error codes weren't checked for or handled).

Much of the examples (!) in MSDN are also full of code where error codes
aren't checked, and therefore would not be detected.


On the other hand, if exceptions are used, the program _has_ to handle them,
or it terminates. This means they can't go undetected.

I've never liked error handling with error codes. Even BASIC's ON ERROR ...
uses a method similar to exceptions, rather than error codes.

If you use error codes, you can either;

a) Check all error codes, and handle them, which tends to lead to a nested
mess of if-else, where it either handles it, or passes it on, essentially
manually emulating the exception handling. This code tends to completely
obfuscate the program logic of the actual code, by burying it in
error-checking code, making it hard to follow the normal execution path.

This would also make it slower than exceptions, because of all the if-else
tests.

Exceptions can be implemented efficiently, with practically no run-time
impact, if no exception is thrown, e.g. using address-range tables,
generated at compile-time, to find out what to do, if an exception is
thrown.


b) Not check error codes. In that case, you have a buggy program.

Slow and obfuscated, or buggy. Take your pick.

This is why exceptions were made. To overcome these problems.

With exceptions, you avoid both problems, and it cleanly separates the
program logic from the error handling code.


> I am not saying 'prefer error codes to exceptions'. I think that both
> have a part to play in program design. I am saying that which you
> choose depends on how important it is for the caller to know what went
> wrong. If it is really important and it is just as likely the call
> will fail a suceed, then I propose we have a contract of the form:
>
> do the work OR (don't and say why not via an error code)
>
> If on the other hand we have a contract where it is anticipated that
> the contract will be honoured 99% of the time and that failure
> indicates something like a programming bug or serious and RARE
> mis-configuration, then exceptions should be used. I would not make
> them part of the contract because that would mean that the caller
> needs to know so badly that an error code approach would be better for
> the caller.

So, the exceptions a function could throw, should not be documented (not
necessarily in the program)?

Earlier, you said that they should. That's what lead me to believe that we
agreed.

If they are not documented, a caller can only use "catch(..)" to catch any
exceptions, and have no way of doing anything about them. What's the use of
unknown exceptions?

If, on the other hand, you think they should be documented, so they can
caught specifically, then I think we agree. Whether or not you call the
specified exceptions a part of the contract, then is just a matter of what
you call it. For me, I think it's reasonable to consider documented
exceptions part of the contract.


> > You suggest having specified exceptions (documented exceptions, they
don't
> > need to be documented in the program code as throw-clauses).
>
> Ah but they do. This was a late-breaking discovery of mine by reading
> the std. See section 17.4.4.8 clause 1.

I only have the draft version of the standard (linked from Bjarne
Stroustrup's page). Could you have quoted the relevant part?


> > These documented exceptions constitute the "What happens if the contract
is
> > broken"-part.
> >
> > Like I mention below, here, such specification may be considered part of
the
> > contract, no matter if it's expressed in the code, or not.
>
> This is the great debate now.

Well, if this is what it's all about, then I consider it nothing to argue
about. :)

Then it's just a matter of what you call it, and it doesn't have any
implications on the program.

At least the way exception specifications are, currently.

However, you do reply to this, next, here.


> I think that what we do with ES depends
> on the answer to this question. My original proposal was because I
> assumed that the above statement was true. I have now changed my mind.

So, if you consider exceptions not part of the contract, they shouldn't be
documented, like with throw-clauses?

If you don't consider them part of the contract, then what do you consider
exceptions are?

I mean, what are their advantage, in this view, and how can they be used
meaningfully, in a program?


> But I welcome the debate because it is not an easy question and the
> debate helps us all become aware of the issues. This thread is
> starting to get rather large now so I would like to shift it to a new
> thread that deals just with this question.

That's fine.


> > So we really agree.
>
> I don't think we do. It seems to me that you agree with what I thought
> originally, that exceptions do comprise part of the contract. However,
> I no longer think this. IMO the need for static checking hinges on
> this.

In that case, I'm curious to the questions above. What are exceptions for?


> > I can't understand why you think documented exceptions would make the
> > contract weaker (in that case, you're arguing for a weaker contract?
:) ).
> > Like I said, on the contrary.
>
> I wish I had never said this now. It is very misleading. I cocked it
> up. Sorry. When I wrote that I was thinking that a weak contract was
> one in which people wouldn't feel keen to sign up to because it
> contained so many weasel-words that no-one would feel that it had high
> chances of being honoured.

I think I understand what you mean. Like the common EULAs, right? :)

In other words, they boil down to "We have no responsibility, if things go
wrong."

However, that's completely different than exception specifications.

To take the ordinary contracts analogy, again. If you don't use
exception-specifications (and any exceptions aren't documented, if the
function uses it, at all, or uses some other way of failing, like
chrashing), the the contract is basically: "Here's the preconditions,
postconditions and invariants. If things go wrong, either in an incorrect
calling, or somehow failure to fulfill the request at our end, we'll uhm...
Well, we certainly won't tell you what we'll do. Just keep guessing. We'll
just let your imagination run wild. Enjoy."

That doesn't seem like a good contract, to me.


If, on the other hand, any exceptions are clearly documented (or error
codes, but I prefer exceptions), then the contract specifies the
consequences. Then you can actually do something about it. It means full
disclosure of what will happen.

These aren't weasel-words. If something goes wrong, something goes wrong.
Then you can either report it (documented exceptions or error codes), or not
report it (let the program fail, or silently fail).

I think that having documented exceptions is the responsible way, because
then you know what happens, no matter what the circumstances are.


I still can't understand why you think that specifying the complete
behaviour of a function, including behaviour in the presence of error
conditions (no matter how they are reported, as error codes, or exceptions.
Shouldn't error codes be documented, either? Then it at least would be
consistent) would make a contract weaker, in the sense that the function
gets away with things it would otherwise not. It doesn't.

So why would you say that this is like a weasel-words contract (not taking
any responsibility)?

That's a very bad description of the current exception documentations.

Just to make it clear what I mean, do you think the exceptions in the
standard library, just because they are documented, constitutes weasel-word
contracts, for the functions that uses them?

If not, what makes that different from documented exceptions, in general?
(Note, I'm not talking about throw-clauses, here. That's independent of all
this.)


I got some things cleared up, in your reply, but other things, like the
above, left me a little confused, again. But at least, it's an interesting
discussion. :)


> Of course some people DO like to sign such contracts because they are
> so afraid of what will happen if the job is NOT done that they want to
> cover all bases without lots of wrangling in court. However when I see
> such a contract it makes me think the the other party is very worried
> about what will happen if he fails to meet his part of the deal. I
> then say to myself "Why is he this worried? Does he think he might not
> be able to do it after all?"

Uhm. Let's make this concrete.

Let's say we have a simple function, like the one below (it's deliberaty
minimal, only one one parameter, and no return value, to make it simple)::

---

void read(FileHandle f)
{
// Read from file
}

The precondition is: The filehandle must be valid.
The postcondition is: Something is read from the file.

Errors can happen in the following cases:

The file handle is invalid
There was an I/O error (but the file handle was valid)

---

I think the contract-example you come with is too far-fetched from
programming, and I'm not able to map it to an example, such as this one.
Could you demonstrate how the contract-example you gave here would work, in
this example?


In real life, such contracts that you mention, is usually because they (or
others) have got unreasonable claims in the past, like someone stumbling
over a stone on their lawn, and sue the owner of the lawn (This has actually
happend. :) I read about it in a section about the most stupid lawsuits that
were dismissed, that year).

Thus, they cover themselves, not because they think they wouldn't uphold a
contract, but to guard against unreasonable claims.

This is also, in part some of the reason for the way EULAs are.

In addition, they can protect the company, even if they give out bad
software, and then they are bad contracts, yes.


However, the way I see it, this has nothing to do with documenting
exceptions.

I invite you, again, to specify, preferably concretely (like using a code
example), in what way that would be.


Also, how would you do it in my code-example above, without documented
exceptions or error codes? Just silently ignore the error?

That's like saying, "Well, either you didn't uphold your part of the
contract, or we're not upholding our part, but we certainly won't tell you
about it." Now, that's _not_ responsible.

In my opinion, documenting the exceptions is the opposite of weasel-word
contracts. With documented exceptions, the function takes responsibility, no
matter what happens, and specifies clearly up-front, what its behaviour will
be, in any circumstance.

However, not documenting exceptions, that would be more like weasel-word
contracts. Because in that case, the functions says: "Look, I gave you the
preconditions, and even if something failed at our side, it's not our
responisibility, as error-conditions are not part of the contract, so we
won't report it. You can't sue us."

_That_ would be a weasel-word contract, I think.

Thus, I come to the opposite conclusion as you.


What does others in the newsgroup think?


>. In real life this can be useful but I
> think it is not so useful in programming unless the failure scenarios
> are just as likely as the success scenarios. When this is the case I
> think it is better to have a contract that says:
>
> do the work OR (don't and say why not via an error code)

How would this be different from: Do the work OR (don't and say why not by
throwing a documented exception (just like a documented error code)?


> > There may be just a misunderstanding, since we seem to agree, otherwise.
>
> I think this is just a misunderstanding because I used the phrase
> 'weak contract' to refer to a contract that contains lots of
> weasel-words. I shouldn't have done that. I can see now that some
> people would think that this makes it a strong contract because it
> covers all bases. Contracts like this are useful in the real world.
> However, such a *programming* contract would make me think that the
> other party was too concerned with things going wrong.

As mentioned, please provide a concrete example, so I can understand how
such real world contracts would map to using documented exceptions (and how
it would be different from documented error codes).


> We both agree that exceptions are
> what happens when the contract is broken but I am saying that this is
> so exceptional that you would not try to cover all bases.

Well, you can have well-defined exceptions. If I were to provide an example,
using my code above, there could be one exception for InvalidFilehandle, and
one or more for any other thing that may go wrong. These are also specific,
and are thrown if that happens.

If you return an unspecified error code, or unspecified exception, the
calling code will have no idea of _why_ the function failed (if it detects
it at all), and therefore can't take any meaningful steps in doing anything
about it, including giving an error message.

Therefore, you would get one of these clueless error messages like,
"Something went wrong, but we don't know what." Translation: We can't find
our behind with both hands.

:)

That would be just silly.


> > > > Yes, exceptions are thrown if the contract is broken. So far so
good.
> > > > However, it should also be part of the contract, to specify what
the
> > > > consequences are, if the contract is broken.
> > > > This is similar to ordinary contracts.
>
> Yes it is but this is where real world contracts and programming
> contracts differ. Real people are concerned with what happens if the
> other party cannot meet its obligations because that is always a
> possibility.

That's also the case in programs. If a program ignores the possibility of
errors, then, uh, then you get much of the current software we have now. :)
In other words, bad software.


> But in programming I believe it should be so rare that
> 99% of the time the coder should not worry about it. Yes, provide a
> means of catching the exception for those that do care but do not
> expect it to be caught very often (except in main of course).

But if it's not specified, it can't be handled, any other way than to just
absorb it, or terminate the program.

By the way, I tend to just have a catch(), in main(), too. That's because
try-catch, unlike just having support for exceptions in the program, can
affect the efficiency quite a bit. So I use resource handling using class
encapsulation, instead.

However, the exceptions, when caught, carry information about where they
came from, and what the problem was, so I can print a useful diagnostic.

That would not be possible with unspecified exceptions.


> > I agree with you, as mentioned earlier, that the ES in C++, now, aren't
that
> > much use, since they are only checked at run-time, and then it's really
too
> > late to do anything about it.
>
> When I thought that an ES was part of the contract I thought that C++
> should make it more contractual by strong static checking. I still
> think that static checking is better than runtime checking and that it
> makes contracts that people have more confidence in but I no longer
> think that the ES is part of the contract.

There may be a misunderstanding, here. (Really? :) ).

I'm not talking about ES, in terms of throw-clauses. I've deliberately used
"documented exceptions", rather than "exception specifuications", to make
clear that I only mean that the exceptions that can be thrown, are
documented somehow, like in the documentation.

This would enable the calling functions to do anything meaningful about
them, if an exception is thrown.

This is, by the way, the current state of affairs. Without throw-clauses.


Regards,

Terje Slettebo

tslettebo at chello dot no.

Dave Harris

unread,
Nov 27, 2001, 6:54:01 PM11/27/01
to
ap...@student.open.ac.uk (apm) wrote (abridged):
> > And of course [the no-throw guarantee] is crucial, for

> > writing exception-safe code, so it deserves support.
>
> Maybe this is something I have missed. Would you please give an
> example ?

In order to write exception-safe code, it is often useful to separate the
routines which may throw from those which don't. For example, suppose we
do MyClass assignment like this:

class MyClass {
std::vector<Item> m_items1;
std::vector<Item> m_items2;
public:
MyClass &operator=( const MyClass &rhs ) {
m_items1 = rhs.m_items1;
m_items2 = rhs.m_items2;
return *this;
}
//...
};

This has a problem. The vector assignment will involve copying the Items,
and if we get an exception while copying m_items2 we are stuffed. We can't
complete the assignment, and there is no way to undo the change we already
made to m_items1. Any class invariants we might have had, eg saying that
both vectors had the same size, will have been lost.

We would much prefer assignment to be "all or nothing"; either it
completes normally, or else it fails and the target is unchanged. We can
achieve that by doing all the copying first, to temporaries, before
changing any instance variables:

MyClass &operator=( const MyClass &rhs ) {
std::vector<Item> temp1( rhs.m_items1 );
std::vector<Item> temp2( rhs.m_items2 );
m_items1.swap( temp1 );
m_items2.swap( temp2 );
return *this;
}

Now if there is an exception during the copying, at least the two instance
variables remain undisturbed.

Of course, we have the same problem if m_items2.swap() throws. Once we
have swapped m_items1, we must ensure nothing else throws until the
assignment is complete. Specifically, we need std::vector::swap() to
guarantee it will not throw.

Fortunately, it is usually easy to write a non-throwing swap() because it
does not need to allocate resources. It just moves around the resources it
already has. So the above formulation is a viable solution. In practice,
we know that other people might want to swap MyClasses too, so it is usual
to factor that out into another routine. The copy-construction of vectors
is already being done in MyClass's own copy constructor, so the canonical
assignment actually looks like:

MyClass &operator=( const MyClass &rhs ) {
MyClass( rhs ).swap( *this );
return *this;
}

(Which is small enough to be inlined, incidently.) You can find out more
about this in chapters 8 to 19 of Herb Sutter's "Exceptional C++". It is
unobvious but important.

Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
bran...@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Artem Livshits

unread,
Nov 28, 2001, 8:06:04 AM11/28/01
to
"apm" <ap...@student.open.ac.uk> wrote in message
news:d1a33011.01112...@posting.google.com...

> Please note that the debate has shifted now. It is no longer about the
> ES; it is now "does the ES form part of the contract?".

A list of exceptions that might be thrown usually doesn't; garantee of their
absence often does, IMHO.


Artem Livshits
Brainbench MVP for C++
http://www.brainbench.com

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Davide Bolcioni

unread,
Nov 29, 2001, 6:54:48 AM11/29/01
to
apm wrote:

> Here's a concise summary of my proposal for stricter exception
> specifications:
>

> By using the word 'onlythrow' instead of 'throw', exception
> specifications are subject to static checking and single level
> propagation. Violations of an onlythrow list are a compilation error.
> Such errors only apply to functions that have an onlythrow list.
> Functions that do not have an onlythrow list that call routines that
> do are not affected. Functions with an onlythrow list may not call
> functions with a throw list since such functions might call
> unexpected. A compiler that implements onlythrow must ship with a
> standard C++ library that uses onlythrow rather than throw in its
> exception specifications.


You might want to look at a similar proposal from me, titled
"[C++0x] Extended exception specifications", which addresses the
same issue and faced similar objections.

Consider the vector<> template as it is now (can throw anything):

explicit vector(size_type n, T const & init = T());

1. Under my proposal, you might declare:

explicit vector ... throw(...); // Can throw anything

but define

vector ... catch()

which still means "can throw anything" because it catches nothing,
please compiler compute a list of what could be thrown (at template
instantiation) and make use of it when inlining, especially when
it turns out to be empty.

2. You might want to promise some more in the definition:

explicit vector ... catch(logic_error); // Can throw anything BUT
// logic error.

which means please compiler complain loudly if the implementation
ever attempts to leak a logic_error exception in the definition.

3. You might want to promise and threaten

explicit vector ... catch(logic_error) throw(bad_alloc);

which means "you need not worry about logic_error but a bad_alloc is
entirely yours to deal with", with the compiler complaining upon
logic_error as above.

4. You might want to be bold

explicit vector ... catch(...)

which means "any exception is guaranteed to be taken care of" and
please compiler never scream if I forgot any.

5. You might want to be real safe, just in case someone plays with
function pointers and other C++ oddities, by saying:

1a) explicit vector ... catch() throw(...)
2a) explicit vector ... catch(logic_error) throw(...)
3a) (unchanged)
4a) explicit vector ... catch(...) throw()

where *in addition* to static checking runtime checking code is
emitted to trigger the usual unexpected() behavior - because if
the static checks are circumvented or cast away, you might want
some extra protection, e.g. from poorly behaved plugins.

It is also my opinion that exceptions != DbC, e.g. in the "open
file" case, "file exists" might be a precondition for "open for
reading" (if the interface says so) but "FAT is hosed by disk
error" is most certainly an exception.

Just my 0.02 Euros.

Davide Bolcioni
--
Paranoia is an afterthought.

Terje Slettebø

unread,
Nov 29, 2001, 7:14:16 AM11/29/01
to
"apm" <ap...@student.open.ac.uk> wrote in message
news:d1a33011.01112...@posting.google.com...
> Terje Sletteb <clcppm...@this.is.invalid> wrote in message

news:<3scM7.4439$Sa4.6...@news01.chello.no>...
> > "apm" <ap...@student.open.ac.uk> wrote in message
> > > It follows from this that the exceptions such a function may throw
> > > should not be a part of the contract. After all, the exceptions only
> > > occur when all bets are off.
> >
> > If this is done, it begs the larger question: How do you deal with
> > exceptions that the function may throw, if you don't know which (if any)
> > exceptions it may throw (no matter if it's documented in
> > throw-specifications, or not)?
>
> By-and-large I would not expect you to. After all if it was *that*
> important to know then it ought to be part of the contract. If it
> cannot be part of the contract, like with constructors or overloaded
> [] operators, say, then the exceptions that might be thrown should be
> documented. This is the approach taken by the C++ standard. Where an
> app really needs to know more about the exception (and there are cases
> sometimes) then I would manage this using inheritance. The whole
> project would have a single base class for exceptions and more
> specific exceptions would inherit from this. This enables anyone
> interested in the derived type to catch it by derived type. Again, all
> this would have to be documented rather than using exception
> specifications.

I have been talking about documenting them. Whether or not one use
throw-clauses for this, is really another issue.

What I, and many others in the thread, have reacted to, is that you meant
they are not part of the contract, and therefore shouldn't be documented.
This would mean they could only be caught with "catch(...)" making typed
exceptions useless.

I've made it very clear that I was talking about _documenting_ exceptions
(so they could be caught using "catch(<exceptiontype> ...)"), and that it
didn't have to do with throw-clauses.

Now, you're saying they can be documented, after all.

What do you really mean? Can they be documented, or can't they be
documented?

If you mean they can be documented, then that's really what I and many other
people here have been saying, too. That they have to be documented, so they
can be caught as specific exceptions.


You mentioned the standard, here. This is the way it's done in the standard.
Which exceptions that can be thrown, are clearly documented.

Whether or not you call the documented exceptions part of the contract, or
not, is really just what you call it. It doesn't have any impact on the
language. In this case, I consider them part of the contract. So has many
others said, as well.

It makes sense because, as Bob Bell said in the new thread:

>Exceptions are not what happens when a contract is broken. Exceptions
>are a mechanism used to implement this kind of contract:

> do the operation (or don't and say why not)


In my opinion, the difference you make between error codes and exceptions,
is an arbitrary one, like also someone else mentioned. If error codes should
be documented (it would be rather pointless if they weren't), then so should
exceptions. Both are part of the contract.

> Note that according to the standard in section 17.4.4.8 clause 1, an
> implementation may 'strengthen' the ES for a function that is in the
> C++ Standard Library by removing listed exceptions. I believe that
> this supports the view the an ES is not to be viewed as part of the
> contract.

It means the contract can be changed. That's all. By strengthening the
exception specification, the function promises to throw less exceptions, so
it promises more. Therefore, it can be used in a context which expects it to
promise less.


> > Wouldn't this make exceptions essentially useless?
>
> It means that the exceptions that a function might throw have to be
> documented.

Well, then. But like I said, I thought you meant they shouldn't be
documented. What's the point in documenting them, if they are not part of
the contract?


Regards,

Terje Slettebo

apm

unread,
Nov 29, 2001, 5:58:59 PM11/29/01
to
Francis Glassborow <francis.g...@ntlworld.com> wrote in message
news:<$Db1l2EtEnA8Ew$t...@robinton.ntlworld.com>...

> In article <9ts8al$2r54$1...@nntp6.u.washington.edu>, Mary K. Kuhner
> <mkku...@kingman.genetics.washington.edu> writes
> >I would hate to lose this use of exceptions. I don't feel it should
> >be deprecated.
>
> I do not think you should have any fears on this score. Exceptions are a
> powerful and valuable tool in C++. The problem is not with them but with
> Exception Specifications which seem to be flawed.

Exactly. My original proposal notes that ESs are flawed and proposed
an extension to address this. But it pre-supposed that the exceptions
a function might throw form part of the contract itself. I later had
second thoughts about whether or not the exceptions formed part of the
contract.

Whether exceptions are part of the contract or not, I believe the
flaws in ESs are so serious that ESs in their current form should not
be used.

If exceptions are part of the contract then IMO we need a form an ES
that works better. My proposal discusses such a form. A weakness in it
is that it does not address the problems associated with templates.

If exceptions are NOT part of the contract then there is no need to
have strong static checking.

-apm

apm

unread,
Nov 30, 2001, 7:59:21 AM11/30/01
to
bel...@pacbell.net (Bob Bell) wrote in message news:<c87c1cfb.01112...@posting.google.com>...

> > do the work OR (don't and say why not)
>
> This kind of postcondition is independent of the mechanism used to say
> "why not." It can be an error code, a thrown exception, or any other
> viable error-reporting mechanism. Arbitrarily deciding that exceptions
> are a special error-reporting mechanism that somehow don't fit with
> preconditions, postconditions and design-by-contract seems a little
> specious to me.
>
> Bob

After alot of agonising over this I have finally come to the point
where I agree with Bob. In my desire to find a way of implementing my
own personal add-on to C++ that provides DbC (a bit like GNU NANA) I
felt I had to address the issue of exceptions. This included
addressing the weaknesses in the ES that seem to render it useless.
Unfortunately, my thoughts on DbC began to dominate and were wrong on
a number of points, as pointed out by Bob, Mary, Terje and others.

I now think that DbC is a separate issue from exceptions, which I
would like to address at some point but it will be the subject of a
separate post. In the meantime there seems to be general agreement
that the current form of ES is broken. What would people like to do
about it ?

Most people seem to have given up on the idea of a better, statically
checked ES because it seems to be very hard indeed to devise a
mechanism that works satisfactorily in the presence of templates.

I am now working on MARK II of the proposal that addresses templates.
It does not involve any language extensions but is an attempt by
programming convention to employ some sort of constrained genericity
to functions that have an onlythrow ES and that use templates.

Is anyone interested? Or do people think that the problems with ESs
are so deep that they cannot be solved?

Regards,

Andrew M.

Terje Slettebø

unread,
Nov 30, 2001, 10:17:31 AM11/30/01
to
"apm" <ap...@student.open.ac.uk> wrote in message
news:d1a33011.01112...@posting.google.com...

If we could get it to fly, then it could be useful. Meaning that we get it
to handle templates, as well.

With static exception checking, it means you're certain that all exceptions
are caught, and that could definitely be useful. And that it may be
documented that they are caught, like using some kind of ES.


Regarding my own idea, in the new exception-thread. I, too, think that that
way of doing it, may not be such a good way of doing it (eliminating
throw-clauses, yet using static checking), after all, as it doesn't make it
explicit, in the code, which exeptions may be thrown where. Thus, one again
has to rely on documentation, rather than the code itself.

The Java way may be better, after all, if one is to use static ES. Then, the
exceptions that can be thrown by a function, is clearly marked in the
function signature. But then, what about exceptions that can be thrown by
things like mathematical expressions?


Regards,

Terje

Mary K. Kuhner

unread,
Nov 30, 2001, 4:46:19 PM11/30/01
to
>The Java way may be better, after all, if one is to use static ES. Then, the
>exceptions that can be thrown by a function, is clearly marked in the
>function signature. But then, what about exceptions that can be thrown by
>things like mathematical expressions?

Java's approach seems to lose the "intermediate levels don't need to
worry about error handling" quality of C++ exceptions; you end up having
to inform every intermediate layer about the possibility of the exception,
even when there is nothing they can or should do about it.

I wonder if the correct answer might lie in a development tool separate
from the compiler--something that could take source code and annotate
each routine with its list of possible exceptions received. Then the programmer
could look through them and say, for example, "Hm! Looks like there's
some dynamic memory allocation going on here--maybe I'd better be
prepared to catch bad_alloc." Or "Hm! Sure, this code can throw a
math error in theory, but if I've done my job correctly it won't, so I'll just
let that go through and call terminate()." Or "Good heavens, my homebrew
exception could get out to here?! That can't be right."

But maybe the output would be overwhelming. I'm not sure.

Mary Kuhner mkku...@genetics.washington.edu

David Abrahams

unread,
Dec 1, 2001, 6:37:34 AM12/1/01
to
"Mary K. Kuhner" <mkku...@kingman.genetics.washington.edu> wrote in message
news:9u8m4s$uj4$1...@nntp6.u.washington.edu...

> >The Java way may be better, after all, if one is to use static ES. Then,
the
> >exceptions that can be thrown by a function, is clearly marked in the
> >function signature. But then, what about exceptions that can be thrown by
> >things like mathematical expressions?
>
> Java's approach seems to lose the "intermediate levels don't need to
> worry about error handling" quality of C++ exceptions; you end up having
> to inform every intermediate layer about the possibility of the exception,
> even when there is nothing they can or should do about it.

The remark above is very much to-the-point. I have serious concerns that
strict checking of exception specifications would dramatically increase
busywork for programmers while providing little or no real improvement in
program robustness.

> I wonder if the correct answer might lie in a development tool separate
> from the compiler--something that could take source code and annotate
> each routine with its list of possible exceptions received. Then the
programmer
> could look through them and say, for example, "Hm! Looks like there's
> some dynamic memory allocation going on here--maybe I'd better be
> prepared to catch bad_alloc." Or "Hm! Sure, this code can throw a
> math error in theory, but if I've done my job correctly it won't, so I'll
just
> let that go through and call terminate()." Or "Good heavens, my homebrew
> exception could get out to here?! That can't be right."
>
> But maybe the output would be overwhelming. I'm not sure.

Now, /that's/ a good idea. I wish that at least one of the many people who
have called for strict ES checking would implement it, so that people could
try it and report on their experience. I would hate to see the feature added
to the language without extensive experience because I'm certain many people
would use it right away, likely with corresponding negative repercussions
for the users and maintainers of their code.

The tool you propose seems like it would allay the fears of people who think
they can't write a robust program without ES checking.

-Dave

Terje Slettebø

unread,
Dec 1, 2001, 3:09:06 PM12/1/01
to
"David Abrahams" <david.a...@rcn.com> wrote in message
news:9u9gms$2rs$1...@bob.news.rcn.net...

> "Mary K. Kuhner" <mkku...@kingman.genetics.washington.edu> wrote in
message
> news:9u8m4s$uj4$1...@nntp6.u.washington.edu...
> > >The Java way may be better, after all, if one is to use static ES.
Then,
> the
> > >exceptions that can be thrown by a function, is clearly marked in the
> > >function signature. But then, what about exceptions that can be thrown
by
> > >things like mathematical expressions?
> >
> > Java's approach seems to lose the "intermediate levels don't need to
> > worry about error handling" quality of C++ exceptions; you end up
having
> > to inform every intermediate layer about the possibility of the
exception,
> > even when there is nothing they can or should do about it.
>
> The remark above is very much to-the-point. I have serious concerns that
> strict checking of exception specifications would dramatically increase
> busywork for programmers while providing little or no real improvement in
> program robustness.

I gave reply to this, to Mary's message, when I finally found it on
Dejanews.


> Now, /that's/ a good idea. I wish that at least one of the many people who
> have called for strict ES checking would implement it, so that people
could
> try it and report on their experience. I would hate to see the feature
added
> to the language without extensive experience because I'm certain many
people
> would use it right away, likely with corresponding negative repercussions
> for the users and maintainers of their code.
>
> The tool you propose seems like it would allay the fears of people who
think
> they can't write a robust program without ES checking.

Have you cheked the tool proposed in the new thread? It's similar, but it
checks it against the exception specifications, so it only shows the cases
where the exception specifications don't cover all possible exceptions that
may be thrown. That would save going through all the output, and it will
only show the cases where it's not specified. That way, you can check that
part of the code, and determine whether or not an exception may be thrown
there.


Regards,

Terje Slettebo

Terje Slettebø

unread,
Dec 1, 2001, 4:35:11 PM12/1/01
to
mkku...@kingman.genetics.washington.edu (Mary K. Kuhner) wrote in message
news:<9u8m4s$uj4$1...@nntp6.u.washington.edu>...

I didn't actually get this message, as it didn't show up in the messages I
got. I was only alerted to its presence by chance, since David Abrahams
quote from it. Thanks, my ISP, thank you very much... :)

Therefore, I went to Dejanews, and found it there.

> >The Java way may be better, after all, if one is to use static ES. Then,
the
> >exceptions that can be thrown by a function, is clearly marked in the
> >function signature. But then, what about exceptions that can be thrown by
> >things like mathematical expressions?
>
> Java's approach seems to lose the "intermediate levels don't need to
> worry about error handling" quality of C++ exceptions; you end up having
> to inform every intermediate layer about the possibility of the exception,
> even when there is nothing they can or should do about it.

Yes, I know.

But what if you use them in another context? For example if you call the
function in another context. Without specification, there will be no way the
calling function will know what exceptions to expect, unless they are
documented, somewhere, since it's not present in the signature.

I think this is a valid point, too.


> I wonder if the correct answer might lie in a development tool separate
> from the compiler--something that could take source code and annotate
> each routine with its list of possible exceptions received. Then the
programmer
> could look through them and say, for example, "Hm! Looks like there's
> some dynamic memory allocation going on here--maybe I'd better be
> prepared to catch bad_alloc." Or "Hm! Sure, this code can throw a
> math error in theory, but if I've done my job correctly it won't, so I'll
just
> let that go through and call terminate()." Or "Good heavens, my homebrew
> exception could get out to here?! That can't be right."

Yes. That would definitely improve the current situation.

If we are to be frank with ourselves, almost anything will improve the
current situation. :)

There's also a proposal for a tool similar to that, in the new thread
("Exceptions, DbC and broken contracts"), where a tool could check the
exception specifications against the code, and determine if they cover all
exceptions that may be thrown. This way, calls to unexpected() could be
avoided.


> But maybe the output would be overwhelming. I'm not sure.

As mentioned above, it could match it against exception specifications, and
only give a warning or error if there's a discrepancy. That could actually
make exception specifications useful.


Regards,

Terje Slettebo

David Abrahams

unread,
Dec 1, 2001, 7:08:55 PM12/1/01
to

"Terje SlettebĹł" <tsle...@acm.org> wrote in message
news:EF4O7.5471$Sa4.6...@news01.chello.no...

> Yes, I know.
>
> But what if you use them in another context? For example if you call the
> function in another context. Without specification, there will be no way
the
> calling function will know what exceptions to expect, unless they are
> documented, somewhere, since it's not present in the signature.

What's wrong with writing "boy scout" functions, that are prepared for
anything? It isn't that hard to do.

> > I wonder if the correct answer might lie in a development tool separate
> > from the compiler--something that could take source code and annotate
> > each routine with its list of possible exceptions received. Then the
> programmer
> > could look through them and say, for example, "Hm! Looks like there's
> > some dynamic memory allocation going on here--maybe I'd better be
> > prepared to catch bad_alloc." Or "Hm! Sure, this code can throw a
> > math error in theory, but if I've done my job correctly it won't, so
I'll
> just
> > let that go through and call terminate()." Or "Good heavens, my
homebrew
> > exception could get out to here?! That can't be right."
>
> Yes. That would definitely improve the current situation.
>
> If we are to be frank with ourselves, almost anything will improve the
> current situation. :)

When I am frank with myself (and you) I have my doubts that there is
actually a problem. Do you have an example of a concrete programming
scenario where, if you don't know everything that might be thrown, there is
an insurmountable problem?

> There's also a proposal for a tool similar to that, in the new thread
> ("Exceptions, DbC and broken contracts"), where a tool could check the
> exception specifications against the code, and determine if they cover all
> exceptions that may be thrown. This way, calls to unexpected() could be
> avoided.

But avoiding calls to unexpected() is SO EASY: just avoid
exception-specifications!

> > But maybe the output would be overwhelming. I'm not sure.
>
> As mentioned above, it could match it against exception specifications,
and
> only give a warning or error if there's a discrepancy. That could actually
> make exception specifications useful.

Seriously: how? What would you use them for? catch(...) can always be used
to capture an unanticipated exception type.

-Dave

Terje Slettebø

unread,
Dec 2, 2001, 12:56:01 PM12/2/01
to
"David Abrahams" <david.a...@rcn.com> wrote in message
news:9uborv$kdi$1...@bob.news.rcn.net...
>
> "Terje Slettebø" <tsle...@acm.org> wrote in message

> news:EF4O7.5471$Sa4.6...@news01.chello.no...
>
> > Yes, I know.
> >
> > But what if you use them in another context? For example if you call the
> > function in another context. Without specification, there will be no way
> the
> > calling function will know what exceptions to expect, unless they are
> > documented, somewhere, since it's not present in the signature.
>
> What's wrong with writing "boy scout" functions, that are prepared for
> anything? It isn't that hard to do.

You can do that, of course.

But unless any exceptions are documented, that's the only thing you can do
(catch using "catch(...)"). You can't even get the name of the exception, or
what it's about, because it may be of any type.

For example, if a function to open a file, throws the exception FileNotFound
(or use a documented error code for that), then the calling function knows
what happens, and can react meaningfully to it.

As it has been pointed out by others, here, exceptions is just one way of
signalling error conditions, or other signals. If you think exceptions
shouldn't be documented, in the documentation, don't you think return codes
should be documented, either?

If so, how would you know what happened, if something went wrong, and how to
deal with it?


The issue here isn't whether or not exceptions should be documented, but
whether or not one should use throw-clauses as a documentation.

However, the way you answered, seemed to indicate that the calling function
didn't need to know anything about what may happen (regardless of whether
it's documented using throws-clauses, or not), so that's what I answered to,
now.


> > > I wonder if the correct answer might lie in a development tool
separate
> > > from the compiler--something that could take source code and annotate
> > > each routine with its list of possible exceptions received. Then the
> > programmer
> > > could look through them and say, for example, "Hm! Looks like there's
> > > some dynamic memory allocation going on here--maybe I'd better be
> > > prepared to catch bad_alloc." Or "Hm! Sure, this code can throw a
> > > math error in theory, but if I've done my job correctly it won't, so
> I'll
> > just
> > > let that go through and call terminate()." Or "Good heavens, my
> homebrew
> > > exception could get out to here?! That can't be right."
> >

> > Yes. That would definitely improve the current situation.
> >
> > If we are to be frank with ourselves, almost anything will improve the
> > current situation. :)
>
> When I am frank with myself (and you) I have my doubts that there is
> actually a problem. Do you have an example of a concrete programming
> scenario where, if you don't know everything that might be thrown, there
is
> an insurmountable problem?

This was regarding the use of exception specifications, not exceptions in
general.

If using exception specifications, an unspecified exception can result in a
call to terminate(), which calls abort(), without letting any possible outer
handler take care of it, not even a catch-all handler.

Since we are talking about exception specifications, this is what I referred
to as "the current situation."

Given that, can you now understand why I said that almost anything can
improve those exception specifications?

This is also something that others in the thread have expressed.

Seems it maybe was just a misunderstanding.


> > There's also a proposal for a tool similar to that, in the new thread
> > ("Exceptions, DbC and broken contracts"), where a tool could check the
> > exception specifications against the code, and determine if they cover
all
> > exceptions that may be thrown. This way, calls to unexpected() could be
> > avoided.
>
> But avoiding calls to unexpected() is SO EASY: just avoid
> exception-specifications!

Yes.

But why do you think exception specifications were made, in the first place?

They were made to ensure that all exceptions are caught (one way or the
other). Unfortunately, the "one way or the other" decision happens at
run-time, so if one exception is thrown, that isn't specified, it's "caught"
by a call to unexpected().


> > > But maybe the output would be overwhelming. I'm not sure.
> >

> > As mentioned above, it could match it against exception specifications,
> and
> > only give a warning or error if there's a discrepancy. That could
actually
> > make exception specifications useful.
>
> Seriously: how? What would you use them for? catch(...) can always be used
> to capture an unanticipated exception type.

They are actually very useful.

If, for example, you know that a function can throw an IOException, then the
calling function can know that, and can catch that particular exception, and
do something meaningful about it (including giving an error-message).

Without that, it will be no way to do anything meaningful about it, like I
said above, you can't even get the name of the exception, if you don't know
the type.

This is also why exception specifications exists in Java, and are statically
checked (at compile-time), there. This ensures that all exceptions are
caught, and there's no risk for any unexpected() call, since that is not
used.

Besides, using static checking, means the exception specifications there
have zero run-time overhead, unlike the C++ exception specifications.


Regards,

Terje Slettebo

apm

unread,
Dec 2, 2001, 7:50:25 PM12/2/01
to
"David Abrahams" <david.a...@rcn.com> wrote in message news:<9u9gms$2rs$1...@bob.news.rcn.net>...
[snip]

> I have serious concerns that
> strict checking of exception specifications would dramatically increase
> busywork for programmers while providing little or no real improvement in
> program robustness.

I don't quite follow. Why would it be extra work for an optional
facility? Surely it's only extra work for those that want to use it?
Also, are you saying that strict ES checking provides little or no
improvement? I disagree. In D&E it discusses the benefits but also the
tradeoffs that leave us with the current form, where checks are done
at runtime.

> > I wonder if the correct answer might lie in a development tool separate
> > from the compiler

[snip]

> The tool you propose seems like it would allay the fears of people who think
> they can't write a robust program without ES checking.

Perhaps you mean the mythical lint++ mentioned by in Koenig and
Stroustrup in their exception paper in section 8.2 page 15. However,
they do not make any promises about helping to allay the fears of
people that cannot write robust programs. I imagine they would
consider that to be beyond the scope of the paper.

Regards,

Andrew M.

apm

unread,
Dec 2, 2001, 7:53:01 PM12/2/01
to
"David Abrahams" <david.a...@rcn.com> wrote in message news:<9uborv$kdi$1...@bob.news.rcn.net>...
> "Terje Slettebø" <tsle...@acm.org> wrote in message
> news:EF4O7.5471$Sa4.6...@news01.chello.no...

> > Yes. That would definitely improve the current situation.
> >
> > If we are to be frank with ourselves, almost anything will improve the
> > current situation. :)
>
> When I am frank with myself (and you) I have my doubts that there is
> actually a problem.
[snip]

> But avoiding calls to unexpected() is SO EASY: just avoid
> exception-specifications!
[snip]

> > > But maybe the output would be overwhelming. I'm not sure.
> > As mentioned above, it could match it against exception specifications,
> and
> > only give a warning or error if there's a discrepancy. That could actually
> > make exception specifications useful.
>
> Seriously: how? What would you use them for?

ANSI/ISO do consider this to still be an open issue, due to a problem
raised by Herb Sutter. He gives an example of a simple variable
declaration that may fail at runtime with unexpected() due to absence
of strong checking. I mention it in my proposal where I explain how
adding onlythrow() to the destructor fixes it. The issue (219) can be
found at http://www.comeaucomputing.com/iso/cwg_active.html#219

Regards,

Andrew M.

David Abrahams

unread,
Dec 3, 2001, 12:43:11 AM12/3/01
to

"Terje SlettebĹł" <tsle...@acm.org> wrote in message
news:C9fO7.5523$Sa4.6...@news01.chello.no...

> "David Abrahams" <david.a...@rcn.com> wrote in message

> > What's wrong with writing "boy scout" functions, that are prepared for


> > anything? It isn't that hard to do.
>
> You can do that, of course.
>
> But unless any exceptions are documented, that's the only thing you can do
> (catch using "catch(...)"). You can't even get the name of the exception,
or
> what it's about, because it may be of any type.
>
> For example, if a function to open a file, throws the exception
FileNotFound
> (or use a documented error code for that), then the calling function knows
> what happens, and can react meaningfully to it.
>
> As it has been pointed out by others, here, exceptions is just one way of
> signalling error conditions, or other signals. If you think exceptions
> shouldn't be documented, in the documentation, don't you think return
codes
> should be documented, either?

I can't make sense of the second part of that last sentence, but its premise
is false. I do think exceptions should be documented in the documentation.

> If so, how would you know what happened, if something went wrong, and how
to
> deal with it?
>
>
> The issue here isn't whether or not exceptions should be documented, but
> whether or not one should use throw-clauses as a documentation.

I think you really mean "exception specifications", not "throw-clauses".

I've only ever met one person who thought that one should use the current
exception specifications as documentation. I think the issue is actually
whether they should be changed so that they correspond to a requirement
enforced by the compiler.

> However, the way you answered, seemed to indicate that the calling
function
> didn't need to know anything about what may happen (regardless of whether
> it's documented using throws-clauses, or not), so that's what I answered
to,
> now.

That is true of 99.9% of all functions, in my experience. Very few of them
actually do need to know anything about what may happen.

> > When I am frank with myself (and you) I have my doubts that there is
> > actually a problem. Do you have an example of a concrete programming
> > scenario where, if you don't know everything that might be thrown, there
> is
> > an insurmountable problem?
>
> This was regarding the use of exception specifications, not exceptions in
> general.

I'm aware of that. As I understand it, you want enforced exception
specifications so that you can be sure that every function knows everything
that might be thrown at it. Have I misunderstood something?

> If using exception specifications, an unspecified exception can result in
a
> call to terminate(), which calls abort(), without letting any possible
outer
> handler take care of it, not even a catch-all handler.
>
> Since we are talking about exception specifications, this is what I
referred
> to as "the current situation."
>
> Given that, can you now understand why I said that almost anything can
> improve those exception specifications?

Ah, yes. But a useless feature (and I'm not saying ESes are useless, but
that's another discussion) doesn't neccessarily need to be improved: it can
simply be avoided. So I am still unconvinced that there's a problem... other
than that people are perennially attracted to ESes because they don't really
understand what they do.

> > But avoiding calls to unexpected() is SO EASY: just avoid
> > exception-specifications!
>
> Yes.
>
> But why do you think exception specifications were made, in the first
place?

I don't know. I have spoken with Bjarne Stroustrup about this personally,
and never got a rationale that I found convincing. What he said, as I
remember it, was something along the lines of: "some code may want to rely
on the fact that it will only see a limited range of exception types". That
argument doesn't seem to stand up for most applications, since the price
paid for that knowledge is termination. On the other hand, as Andy Koenig
pointed out, for some applications, orderly termination is much better than
a crash.

> They were made to ensure that all exceptions are caught (one way or the
> other).

...and I suppose you spoke with the original proposer of the feature to get
this rationale? ;-)

> Unfortunately, the "one way or the other" decision happens at
> run-time, so if one exception is thrown, that isn't specified, it's
"caught"
> by a call to unexpected().

Thanks for explaining ;-)

> > > As mentioned above, it could match it against exception
specifications,
> > and
> > > only give a warning or error if there's a discrepancy. That could
> actually
> > > make exception specifications useful.
> >
> > Seriously: how? What would you use them for? catch(...) can always be
used
> > to capture an unanticipated exception type.
>
> They are actually very useful.
>
> If, for example, you know that a function can throw an IOException, then
the
> calling function can know that, and can catch that particular exception,
and
> do something meaningful about it (including giving an error-message).

That isn't an example of using an exception specification. That's an example
of using some knowledge about what exceptions may be thrown into a function.
I know it sounds like I'm picking nits with your argument, but please bear
with me. An example of using an exception specification is a programming
scenario where the language feature comes into play. So, let's look at where
an enforced specification might come into play:

1. You re-implement a function to make it multithread-safe. This function is
at the core of your system, e.g. in std::allocator. Now it needs to acquire
a mutex which it didn't need before. The system only has a limited number of
mutexes; if you can't get the mutex you throw an exception. So, you add
no_more_mutexes to the function's exception specification. How many other
functions need to change in order to make the compiler happy? How many
functions actually care about the new exception? Is it worth it?

2. You write a new function which is supposed to report all errors thrown at
it. You give it an exception-specification of throw(), and you're careful to
leave out any catch(...) clause. OK, now this function can't call any other
functions with a throw(...)/missing ES, because that would be a violation.
Every exception that can be thrown at the function must be matched by a
corresponding catch clause. Let's look at the impact on the rest of the
program. To be useful, every function in a call chain from this catch-all
function must have the narrowest possible exception-specification, or you
will end up having to catch broad categories of exceptions. Any time a
function anywhere wants to report a new kind of error, that error must be
propagated back up the chain in ESes to each such catch-all function. Oh,
you say that we can handle that problem by defining exception hierarchies,
and throwing classes derived from some base exception? Careful: the
enforcement you thought you had bought by maintaining all those ESes is now
undermined, because the derived classes contain information about what went
wrong that's unavailable to the reporting function unless it has catch
clauses for each derived class... but the ESes won't enforce that.

> Without that, it will be no way to do anything meaningful about it, like I
> said above, you can't even get the name of the exception, if you don't
know
> the type.
>
> This is also why exception specifications exists in Java, and are
statically
> checked (at compile-time), there. This ensures that all exceptions are
> caught, and there's no risk for any unexpected() call, since that is not
> used.

Except for the special category of unchecked exceptions that had to be
created precisely because strict checking caused such a maintenance
nightmare.

> Besides, using static checking, means the exception specifications there
> have zero run-time overhead, unlike the C++ exception specifications.

That's incorrect: a good C++ compiler does not incur any runtime overhead
for an exception specification (unless an exception is thrown - Java is also
subject to this caveat). In fact, a good C++ compiler can use
exception-specifications to reduce the overall amount of generated code,
which sometimes improves runtime speed.

-Dave

David Abrahams

unread,
Dec 3, 2001, 6:01:11 AM12/3/01
to

"apm" <ap...@student.open.ac.uk> wrote in message
news:d1a33011.0112...@posting.google.com...

> I don't quite follow. Why would it be extra work for an optional
> facility? Surely it's only extra work for those that want to use it?

Lots of people have to use what their company or group is using.
Unfortunately, it's not really a free world out there.

> Also, are you saying that strict ES checking provides little or no
> improvement? I disagree.
> In D&E it discusses the benefits but also the
> tradeoffs that leave us with the current form, where checks are done
> at runtime.

I am familiar with that discussion.
BTW, when I say "strict checking" I mean "strict static (i.e. compile-time)
checking".

So, are you disagreeing with what I actually meant, or something else? If
the former, do you have some real-world experience with strict static
checking which demonstrates that a bug was prevented due to the static
checks; a bug that couldn't have been prevented by simpler programming
practices causing less maintenance overhead?

> > The tool you propose seems like it would allay the fears of people who
think
> > they can't write a robust program without ES checking.
>
> Perhaps you mean the mythical lint++ mentioned by in Koenig and
> Stroustrup in their exception paper in section 8.2 page 15.

Sorry, I haven't read that paper. But no, I don't mean that. I mean a tool
proposed by
"Mary K. Kuhner" <mkku...@kingman.genetics.washington.edu> in message
news:9u8m4s$uj4$1...@nntp6.u.washington.edu...

> However,
> they do not make any promises about helping to allay the fears of
> people that cannot write robust programs. I imagine they would
> consider that to be beyond the scope of the paper.

I never mentioned people who actually can't write robust programs. I was
only talking about people who /think/ that they need static ES checking in
order to do it... so, I'm not sure what you're referring to here.

David Abrahams

unread,
Dec 3, 2001, 6:03:14 AM12/3/01
to

"apm" <ap...@student.open.ac.uk> wrote in message
news:d1a33011.01120...@posting.google.com...

> "David Abrahams" <david.a...@rcn.com> wrote in message
news:<9uborv$kdi$1...@bob.news.rcn.net>...

> ANSI/ISO do consider this to still be an open issue, due to a problem


> raised by Herb Sutter. He gives an example of a simple variable
> declaration that may fail at runtime with unexpected() due to absence
> of strong checking.

I don't see what CWG 219 has to do with strict static checking. None of the
participants in that discussion have mentioned exception specifications, nor
have they mentioned checking exception specifications as a possible
solution. Further, it seems to me highly unlikely, given the way the
conversation has progressed thus far, that this particular problem will be
classified as anything other than NAD.

FWIW, the official home of this issue is:
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_active.html#219


> I mention it in my proposal where I explain how
> adding onlythrow() to the destructor fixes it. The issue (219) can be
> found at http://www.comeaucomputing.com/iso/cwg_active.html#219

Adding onlythrow() to the destructor does not fix the problem cited, because
the problem in the issue has to do with what happens when you don't use
onlythrow. That situation would still exist. I hope Herb will forgive me for
paraphrasing him: he is trying to get the committee to "just come out and
tell users that they're not allowed to throw from destructors, and be done
with it", since there are so many ugly effects associated with throwing
destructors. Presumably, as an educator, he tends to prefer that he can give
people a simple rule that is enshrined by the C++ standard, than to explain
an ugly (but legal) morasse. However, C++ has traditionally allowed some
ugly morasses to exist where neccessary to enable some potentially useful
behavior.

-Dave

Early Ehlinger

unread,
Dec 3, 2001, 12:45:40 PM12/3/01
to
"David Abrahams" <david.a...@rcn.com> wrote in message
news:9udu9q$n1b$1...@bob.news.rcn.net...

> 1. You re-implement a function to make it multithread-safe. This function
is
> at the core of your system, e.g. in std::allocator. Now it needs to
acquire
> a mutex which it didn't need before. The system only has a limited number
of
> mutexes; if you can't get the mutex you throw an exception. So, you add
> no_more_mutexes to the function's exception specification. How many other
> functions need to change in order to make the compiler happy? How many
> functions actually care about the new exception? Is it worth it?

The Standard specifically disallows adding exceptions to the ES of any
Standard Library component (e.g., std::allocator). I would assume this
requirement would stay in play for static-checks ES as well.

In fact, this could be a very simple solution to the static-check ES vs.
templates problem. If a template calls a function which throws something
outside of the template's static ES, then the compiler issues an error - in
other words, the template's static ES is not only a promise to the
template's caller, but a requirement placed upon the code it uses as well.
It is not outside the realm of C++ experience for the template to place
requirements on the template parameters - in fact the Standard is riddled
with such requirements.

> 2. You write a new function which is supposed to report all errors thrown
at
> it. You give it an exception-specification of throw(), and you're careful
to
> leave out any catch(...) clause. OK, now this function can't call any
other
> functions with a throw(...)/missing ES, because that would be a violation.
> Every exception that can be thrown at the function must be matched by a
> corresponding catch clause. Let's look at the impact on the rest of the
> program. To be useful, every function in a call chain from this catch-all
> function must have the narrowest possible exception-specification, or you
> will end up having to catch broad categories of exceptions. Any time a
> function anywhere wants to report a new kind of error, that error must be
> propagated back up the chain in ESes to each such catch-all function. Oh,
> you say that we can handle that problem by defining exception hierarchies,
> and throwing classes derived from some base exception? Careful: the
> enforcement you thought you had bought by maintaining all those ESes is
now
> undermined, because the derived classes contain information about what
went
> wrong that's unavailable to the reporting function unless it has catch
> clauses for each derived class... but the ESes won't enforce that.

This ripple effect /could/ be a negative impact of static ES, to be sure.
However, using a base exception class falls under the category of "promise
less" rather than "lost enforcement." e.g.,

class divide_by_zero : public std::exception { /*...*/ };

double square_root( double )
static throw( divide_by_zero );
/* promises a lot - only possible exception is divide-by-zero */

void square_roots( double* begin , double* end , double* results )
static throw( std::exception );
/* promises very little... could throw divide_by_zero or
std::logic_error or anything else derived from
std::exception. */

Presumably square_roots would use square_root. What you gain from using
static throw is that the compiler verifies that either square_root only
throws functions derived from std::exception, or that you catch anything
else.

I would expect that the further you get from the low-level throwing
functions, the more general your static ES's would become. There is also no
reason one couldn't include the most-derived functions in their ES, as well:

void square_roots( double* begin , double* end , double* results )
static throw( std::exception , divide_by_zero );
/* promises very little.. could throw any std::exception-derivative.
divide_by_zero included more as a hint to the developer than
anything else. */

-- Early Ehlinger

Francis Glassborow

unread,
Dec 3, 2001, 4:24:04 PM12/3/01
to
In article <Z7LO7.37441$py4.22...@news2.nash1.tn.home.com>, Early
Ehlinger <ear...@yahoo.com> writes

>In fact, this could be a very simple solution to the static-check ES vs.
>templates problem. If a template calls a function which throws something
>outside of the template's static ES, then the compiler issues an error - in
>other words, the template's static ES is not only a promise to the
>template's caller, but a requirement placed upon the code it uses as well.
>It is not outside the realm of C++ experience for the template to place
>requirements on the template parameters - in fact the Standard is riddled
>with such requirements.

Are you being serious? Templates such as the containers, auto_ptr etc.
would be completely crippled by such a requirement. If, and I think that
is a big IF, we try to retain ESs then we would have to do much better
than that.


--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

Jani Kajala

unread,
Dec 3, 2001, 4:25:26 PM12/3/01
to
"David Abrahams" <david.a...@rcn.com> wrote in message
news:9uetmc$b02$1...@bob.news.rcn.net...

> So, are you disagreeing with what I actually meant, or something else? If
> the former, do you have some real-world experience with strict static
> checking which demonstrates that a bug was prevented due to the static
> checks; a bug that couldn't have been prevented by simpler programming
> practices causing less maintenance overhead?

Let's say we have a class called File which is used to read files. The class
used to throw only FileNotFound exceptions, but then came need to handle
malformed filenames separately. So MalformedFilename exception was added. All
projects, however, were not properly updated to take this change into account,
and instead of giving user an informative error the next version of another
project started to give "Unkown exception!" messages. Static checking would have
prevented this by warning that MalformedFilename is not handled when the new
version of the other project was compiled.

In general, if you want to make *anything* else with exceptions than print
"Hello world! An exception!" message, then you need to know what exceptions are
thrown. And to know that in high level, you need to know what intermediate level
stuff can throw. And to know what intermediate level stuff can throw you need to
know what low-level stuff can throw... So you need to know *always* what
exceptions can be thrown from a function, even though only a few (or none!) user
functions do anything with that knowledge. As the exceptions need to be
documented in every possible level then why not to check them statically as
well?

The overhead of writing exception specs is not a big deal, you can always
declare a function to throw base classes if you're lazy. So even though File
would throw several different exceptions, users of the class might declare
themselves to throw only a single exception, say IOException.


Regards,
Jani Kajala

"David Abrahams" <david.a...@rcn.com> wrote in message

news:9uetmc$b02$1...@bob.news.rcn.net...

David Abrahams

unread,
Dec 4, 2001, 3:08:34 AM12/4/01
to

"Early Ehlinger" <ear...@yahoo.com> wrote in message
news:Z7LO7.37441$py4.22...@news2.nash1.tn.home.com...

> "David Abrahams" <david.a...@rcn.com> wrote in message
> news:9udu9q$n1b$1...@bob.news.rcn.net...
> > 1. You re-implement a function to make it multithread-safe. This
function
> is
> > at the core of your system, e.g. in std::allocator. Now it needs to
> acquire
> > a mutex which it didn't need before. The system only has a limited
number
> of
> > mutexes; if you can't get the mutex you throw an exception. So, you add
> > no_more_mutexes to the function's exception specification. How many
other
> > functions need to change in order to make the compiler happy? How many
> > functions actually care about the new exception? Is it worth it?
>
> The Standard specifically disallows adding exceptions to the ES of any
> Standard Library component (e.g., std::allocator).

Not so for standard library writers: they are allowed to add arbitrary
implementation-defined exceptions. But anyway, the point stands because you
probably have other functions at the core of your system on which the
standard places no restriction at all.

> I would assume this
> requirement would stay in play for static-checks ES as well.
>
> In fact, this could be a very simple solution to the static-check ES vs.
> templates problem. If a template calls a function which throws something
> outside of the template's static ES, then the compiler issues an error -
in
> other words, the template's static ES is not only a promise to the
> template's caller, but a requirement placed upon the code it uses as well.
> It is not outside the realm of C++ experience for the template to place
> requirements on the template parameters - in fact the Standard is riddled
> with such requirements.

Then everyone would derive their exception classes from std::exception (I
presume that would be in the standard library function's ES) to get around
the compiler and the checks would be useless.


> This ripple effect /could/ be a negative impact of static ES, to be sure.
> However, using a base exception class falls under the category of "promise
> less" rather than "lost enforcement." e.g.,
>
> class divide_by_zero : public std::exception { /*...*/ };
>
> double square_root( double )
> static throw( divide_by_zero );
> /* promises a lot - only possible exception is divide-by-zero */
>
> void square_roots( double* begin , double* end , double* results )
> static throw( std::exception );
> /* promises very little... could throw divide_by_zero or
> std::logic_error or anything else derived from
> std::exception. */
>
> Presumably square_roots would use square_root. What you gain from using
> static throw is that the compiler verifies that either square_root only
> throws functions derived from std::exception, or that you catch anything
> else.

Right. Now, what do you know about the exception object, once you know it is
derived from std::exception? You know "what()" about it, and that's
practically all. You will get an uspecified string possibly not even
appropriate to the locale.

> I would expect that the further you get from the low-level throwing
> functions, the more general your static ES's would become. There is also
no
> reason one couldn't include the most-derived functions in their ES, as
well:
>
> void square_roots( double* begin , double* end , double* results )
> static throw( std::exception , divide_by_zero );
> /* promises very little.. could throw any std::exception-derivative.
> divide_by_zero included more as a hint to the developer than
> anything else. */

Exactly. So, my point is that the ripple effect has an extremely high cost
for code maintenance, while the feature causing the ripple effect has
comparitively few benefits in practice.

-Dave

David Abrahams

unread,
Dec 4, 2001, 3:08:53 AM12/4/01
to

"Jani Kajala" <ja...@REMOVETHIS.sumea.com> wrote in message
news:9ugcq7$h8p$1...@news1.song.fi...

> "David Abrahams" <david.a...@rcn.com> wrote in message
> news:9uetmc$b02$1...@bob.news.rcn.net...
>
> > So, are you disagreeing with what I actually meant, or something else?
If
> > the former, do you have some real-world experience with strict static
> > checking which demonstrates that a bug was prevented due to the static
> > checks; a bug that couldn't have been prevented by simpler programming
> > practices causing less maintenance overhead?
>
> Let's say we have a class called File which is used to read files. The
class
> used to throw only FileNotFound exceptions, but then came need to handle
> malformed filenames separately. So MalformedFilename exception was added.
All
> projects, however, were not properly updated to take this change into
account,
> and instead of giving user an informative error the next version of
another
> project started to give "Unkown exception!" messages. Static checking
would have
> prevented this by warning that MalformedFilename is not handled when the
new
> version of the other project was compiled.

Sure. That problem could have been prevented by simpler programming
practices causing less maintenance overhead than static ES checking, though.

> In general, if you want to make *anything* else with exceptions than print
> "Hello world! An exception!" message, then you need to know what
exceptions are
> thrown.

Not so; you can encode enough of that information as data in a common
exception base class to prevent complete unreportability.

> And to know that in high level, you need to know what intermediate level
> stuff can throw. And to know what intermediate level stuff can throw you
need to
> know what low-level stuff can throw... So you need to know *always* what
> exceptions can be thrown from a function, even though only a few (or
none!) user
> functions do anything with that knowledge. As the exceptions need to be
> documented in every possible level then why not to check them statically
as
> well?

They don't need to be documented at every possible level. You could instead
specify that a given library or large body of code may throw any of the
following exceptions: ....
Then, there are a number of techniques you can use to make it highly
unlikely that any programmer will throw new exceptions without documenting
them. That's a lot simpler and nearly as reliable.

> The overhead of writing exception specs is not a big deal, you can always
> declare a function to throw base classes if you're lazy. So even though
File
> would throw several different exceptions, users of the class might declare
> themselves to throw only a single exception, say IOException.

If you do that, you reduce the already small benefits of static ES checking
to nearly zero.

-Dave

Mary K. Kuhner

unread,
Dec 4, 2001, 6:19:43 AM12/4/01
to
In article <9uborv$kdi$1...@bob.news.rcn.net>,
David Abrahams <david.a...@rcn.com> wrote:

>When I am frank with myself (and you) I have my doubts that there is
>actually a problem. Do you have an example of a concrete programming
>scenario where, if you don't know everything that might be thrown, there is
>an insurmountable problem?

There are certainly plenty of functions that must not throw *anything*.
Destructors, to start with, and also some primitives like swap(), if you
want exception safety elsewhere. Being able to assure yourself that
your swap() cannot throw would be very nice.

catch(...) is one way to accomplish this, but it's basically just saying (if
it absorbs the exception, and there's not much else it can do) "I declare
unilaterally that the code below me *didn't* throw an exception." If
the code below really did, and had reason to do so, frankly your program
probably won't live long even if you don't call unexpected(). I see
catch(...) as a form of defensive programming, and like all such, it can hide
(or worse, obfuscate) errors.

Mary Kuhner mkku...@genetics.washington.edu

apm

unread,
Dec 4, 2001, 6:31:05 AM12/4/01
to
Francis Glassborow <francis.g...@ntlworld.com> wrote in message news:<Vo4Pf+Gq...@robinton.ntlworld.com>...

> In article <Z7LO7.37441$py4.22...@news2.nash1.tn.home.com>, Early
> Ehlinger <ear...@yahoo.com> writes
> >In fact, this could be a very simple solution to the static-check ES vs.
> >templates problem. If a template calls a function which throws something
> >outside of the template's static ES, then the compiler issues an error
[snip]

>
> Are you being serious? Templates such as the containers, auto_ptr etc.
> would be completely crippled by such a requirement. If, and I think that
> is a big IF, we try to retain ESs then we would have to do much better
> than that.

I agree. This was the main thing wrong with my proposal.
For static checking to get anywhere the issue of templates must be addressed.

-apm

apm

unread,
Dec 4, 2001, 6:34:29 AM12/4/01
to
"Jani Kajala" <ja...@REMOVETHIS.sumea.com> wrote in message news:<9ugcq7$h8p$1...@news1.song.fi>...
> "David Abrahams" <david.a...@rcn.com> wrote in message
> news:9uetmc$b02$1...@bob.news.rcn.net...
> Let's say we have a class called File which is used to read files. The class
> used to throw only FileNotFound exceptions, but then came need to handle
> malformed filenames separately. So MalformedFilename exception was added. All
> projects, however, were not properly updated to take this change into account,
> and instead of giving user an informative error the next version of another
> project started to give "Unkown exception!" messages.
[snip]

> In general, if you want to make *anything* else with exceptions than print
> "Hello world! An exception!" message, then you need to know what exceptions are
> thrown. And to know that in high level, you need to know what intermediate level
> stuff can throw. And to know what intermediate level stuff can throw you need
> to know what low-level stuff can throw... So you need to know *always* what
> exceptions can be thrown from a function, even though only a few (or none!)
> user functions do anything with that knowledge.
[snip]
> Regards,
> Jani Kajala

IMO opinion it is potentially useful for exceptions to be types and
for developers to be able to define their own exception hierarchy.
However we get problems because there are occasions, such as the one
above, where we would like to know what the type is because we need to
cater for exceptions of that type. Initially an ES seems to be a good
way to tell people about the types we throw. But it turns out that ESs
are broken. It's all very well to say "don't use them then!" but what
do we do instead?

Perhaps there has been too much emphasis on determining the type of an
exception. After all, when a function returns an integer error code we
do not bother saying what every possible error code value is for the
return value. The programmer has to read the documentation to figure
out what errors there might be.

So one approach would be to have an application exception class, let's
call it AppException, that had an integer private member that acted
like an error code, let's call it 'etype'. Where people might have had
a succession of catch clauses they have just one catch clause for
AppException and inside it they employ a switch statement on the
etype.

The application's only use of ESs would be an empty ES on every dtor.
Any other functions would be understood as potentially capable of
throwing an AppException. This allows distant parts of the app to pass
an exception without it having to mentioned at each point along the
call chain.

I wanted stronger checking for apps that would probably have an
exception hierarchy and where catering for the different types was
important. If I had to live without strong ES checking then with the
exception (groan...) of dtors I would not use ESs and would not have
have an exception hierarchy either. My AppException would be a bit
like the way exceptions are done in Eiffel where this is just one
exception class that has an integer error code.

If later on I found that I really needed to inherit from AppException,
let's call it App2Exception, then I would probably add a virtual
function to AppException that returned 'ekind', which has values that
indicate AppException and App2Exception respectively. I could then
switch on ekind and perform a dynamic cast.

-Andrew M.

Francis Glassborow

unread,
Dec 4, 2001, 6:37:19 PM12/4/01
to
In article <d1a33011.01120...@posting.google.com>, apm
<ap...@student.open.ac.uk> writes

>Perhaps there has been too much emphasis on determining the type of an
>exception. After all, when a function returns an integer error code we
>do not bother saying what every possible error code value is for the
>return value. The programmer has to read the documentation to figure
>out what errors there might be.

Perhaps an idea from another thread might be appropriate. If we enhanced
catch(...) with a method by which the exception type can be reported (at
the same time improve typeid to provide recognisable names) then
programmers would have an easier tool for determining what unexpected
exception had been propagated.


--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Matthew Austern

unread,
Dec 4, 2001, 6:45:59 PM12/4/01
to

> In article <9uborv$kdi$1...@bob.news.rcn.net>,
> David Abrahams <david.a...@rcn.com> wrote:
>
> >When I am frank with myself (and you) I have my doubts that there is
> >actually a problem. Do you have an example of a concrete programming
> >scenario where, if you don't know everything that might be thrown, there is
> >an insurmountable problem?
>
> There are certainly plenty of functions that must not throw *anything*.
> Destructors, to start with, and also some primitives like swap(), if you
> want exception safety elsewhere. Being able to assure yourself that
> your swap() cannot throw would be very nice.

Yes. In practice, that tends to be the distinction I care about:
functions that I know can't throw anything, versus functions that
might throw something. I think what Dave was suggesting is that
once I know that a function might throw, it doesn't matter all that
much exactly which exceptions it might throw.

Davide Bolcioni

unread,
Dec 4, 2001, 6:59:39 PM12/4/01
to
Jani Kajala wrote:

> Let's say we have a class called File which is used to read files. The class
> used to throw only FileNotFound exceptions, but then came need to handle
> malformed filenames separately. So MalformedFilename exception was added. All
> projects, however, were not properly updated to take this change into account,
> and instead of giving user an informative error the next version of another
> project started to give "Unkown exception!" messages. Static checking would have
> prevented this by warning that MalformedFilename is not handled when the new
> version of the other project was compiled.


Enforcing static checking of expression specifications as they stand
now, I reckon, is seen as causing either:
- add expression specification up the call chain to shut up the
compiler, Java-like;
- catching a base class, possibly even std::exception or since we
are at it sprinkling code with throw(...).

In a former post of mine, I suggested extending exception specifications
so that, in your example, members of File have an exception spec of

throw(FileNotFound, MalformedFilename);

but functions calling them can have, among other possibilities:

catch() throw(...)

for a function which does not care about exceptions thrown (this would
be the default) and would have no reason to care about what members of
File throws (this is one of the reasons exceptions were introduced, I
believe), but also

catch(MalformedFilename) throw(...)

for a layer of functions written to shield existing code from the
new exception, and be warned if you forgot any.

> The overhead of writing exception specs is not a big deal, you can always
> declare a function to throw base classes if you're lazy. So even though File
> would throw several different exceptions, users of the class might declare
> themselves to throw only a single exception, say IOException.

I also find the Java ripple effect indesiderable and a maintenance
burden of questionable benefit. Under my proposal, callers have the
option to pass the bucket or ask the compiler to verify that what
the code is intended to do matches how the compiler sees things.

Under my proposal, a non-empty catch specification is a promise to
the caller and as such I guess part of the contract (and possibly
of the function signature, I have not investigated that). An obvious
application of this is to write template destructors as

~some_class() catch(...) throw() { ... code here ... }

and have the compiler complain if e.g. a member destructor throws.

Suppose we had some extra syntax that said

vector(int n, T elem = T()) throw(what invoked members of T throw)

this is a pass-through, just like throw(...). If something is caught
in the body, you add the relevant catch() spec to have the compiler
verify that what you thought you caught got in fact caught, e.g.
an exception could be thrown in a place outside your try ... catch
and you forgot.

Could somebody provide "problem" code, i.e. template code where you
would like to place an exception specification to be statically
verified by the compiler but don't dare because of unexpected() ?

I am specifically interested in the case where exceptions are not
preconditions (loose definition: you can call a true/false function
that would tell you if the operation would fail without attempting
it), in the Eiffel sense.

Davide Bolcioni
--
Linux - the choice of a GNU generation.

Bob Bell

unread,
Dec 4, 2001, 7:00:33 PM12/4/01
to
> Perhaps there has been too much emphasis on determining the type of an
> exception. After all, when a function returns an integer error code we
> do not bother saying what every possible error code value is for the
> return value. The programmer has to read the documentation to figure
> out what errors there might be.

Because of the equivalence between different error reporting methods,
I find reasoning about error codes and exceptions to be quite similar.
If it is valid to state that a programmer must read the documentation
to find out what error codes a function might return, then is it not
also valid to state that a programmer must read the documentation to
find out what exceptions a function might throw?

> So one approach would be to have an application exception class, let's
> call it AppException, that had an integer private member that acted
> like an error code, let's call it 'etype'. Where people might have had
> a succession of catch clauses they have just one catch clause for
> AppException and inside it they employ a switch statement on the
> etype.

I see no reason to abandon different exception types. Remember, very
few functions will even care that an exception is thrown; most
functions will simply allow exceptions to pass through them silently,
calling destructors along the way.

> The application's only use of ESs would be an empty ES on every dtor.

It appears to me that this is the only good use of exception
specifications -- marking functions that won't throw, which are
destructors and other special functions like swap.

> If I had to live without strong ES checking then with the
> exception (groan...) of dtors I would not use ESs and would not have
> have an exception hierarchy either.

This strikes me as throwing the baby out with the bathwater. Just
because exception specifications are not very useful does not demand
or even imply that different exception types should be avoided.

Bob Bell

Early Ehlinger

unread,
Dec 5, 2001, 6:29:26 PM12/5/01
to
"David Abrahams" <david.a...@rcn.com> wrote in message
news:9uh13t$4rp$1...@bob.news.rcn.net...

> > The Standard specifically disallows adding exceptions to the ES of
> > any Standard Library component (e.g., std::allocator).
>
> Not so for standard library writers: they are allowed to add
> arbitrary implementation-defined exceptions.

Not true! Again, the Standard specifically disallows adding
exceptions to the ES of any Standard Library component -
See Section 17.4.4.8, footnote 175:

| 175) That is, an implementation of the function will have an
| explicit exception-specification that lists fewer
| exceptions than those specified in this International
| Standard. It may not, however, change the types of
| exceptions listed in the exception-specification from those
| specified, add others.

> But anyway, the point stands because you
> probably have other functions at the core of your system on which
> the standard places no restriction at all.

The standard often does place restrictions on functions at the
core of your system (albeit sometimes implicitly). For example,
because ~auto_ptr() is declared with throw(), you are restricted
from throwing in the destructor of any class managed by auto_ptr<>.
This is, IMHO, a Good Thing, as destructors should not fail anyway,
but I digress.

> Then everyone would derive their exception classes from
> std::exception (I presume that would be in the standard
> library function's ES) to get around the compiler and
> the checks would be useless.

People could use the same argument against having explicit
types; everybody'll just reinterpret_cast everything and
type-checking would be useless. If a facility for safety
is introduced, wise developers will not abuse it.

> > I would expect that the further you get from the low-level
> > throwing functions, the more general your static ES's would
> > become. There is also no reason one couldn't include the
> > most-derived functions in their ES, as well:
> >
> > void square_roots( double* begin , double* end , double* results )
> > static throw( std::exception , divide_by_zero );
> > /* promises very little.. could throw any std::exception

> > -derivative. divide_by_zero included more as a hint to the
> > developer than else. */


>
> Exactly. So, my point is that the ripple effect has an extremely
> high cost for code maintenance, while the feature causing the ripple

> effect has comparatively few benefits in practice.

There is only a ripple effect if 1 of 2 things occurs:

1) there is no mechanism for "inheriting" ES from called functions,
or for "bubbling up" ES, thus allowing intermediate functions
the luxury of not knowing what exceptions pass through them
while at the same time telling their callers what to expect.

2) you change an interface to an existing function by modifying its
ES.

The former case is the cause of a lot of grief in the Java world, or
so I'm told, and I think that as we strive to improve ES in the C++
world, we should find a mechanism that nullifies this possibility.
I have offered up templatized ES as a possible solution, but I'm sure
somebody will have something better.

The latter case is something which the Language cannot help with,
any more than if you change the parameter list to an existing
function. (Well, assuming that you're using ES at all :)

I don't think static ES would have "few benefits" - it would provide a
mechanism similarly to const; an optional means of codifying the
semantics of your application.

Consider:
class const_fu
{
public:
void checksomething() const;
void dosomething();
void example() const
{
checksomething(); // OK - checksomething is as const as I am.
dosomething(); // ERROR - dosomething is less const than I am.
}
};

class throw_fu
{
public:
void checksomething() static throw();
void dosomething();
void example() static throw()
{
checksomething(); /* OK - checksomething is as
throw-restrictive as
I am. */
dosomething(); /* ERROR - dosomething is less
throw-restrictive than
I am. */
}
};


In both cases, you aren't /required/ to guarantee example is
restricted - you
do so because you want the compiler to help you guarantee a design
requirement. In the former, you do so because you want the compiler's
help guaranteeing that you don't change anything at the wrong time.

In the latter, you do so because you want the compiler's help
guaranteeing you don't throw anything at the wrong time.

const has a ripple effect as well if you don't have it in place from
the
get-go. If you attempt to "go back and const-ify" a class, you
quickly
discover that making one function const can have unintended
consequences
and you end up having to write const-overloads, change other functions
to
be const, etc.

Do you think these burdens of const-correctness outweigh its
usefulness, too?

-- Early Ehlinger

Early Ehlinger

unread,
Dec 6, 2001, 2:39:10 AM12/6/01
to
"Francis Glassborow" <francis.g...@ntlworld.com> wrote

> Early Ehlinger <ear...@yahoo.com> writes
> >In fact, this could be a very simple solution to the static-check ES vs.
> >templates problem. If a template calls a function which throws something
> >outside of the template's static ES, then the compiler issues an error -
in
> >other words, the template's static ES is not only a promise to the
> >template's caller, but a requirement placed upon the code it uses as
well.
> >It is not outside the realm of C++ experience for the template to place
> >requirements on the template parameters - in fact the Standard is riddled
> >with such requirements.
>
> Are you being serious? Templates such as the containers, auto_ptr etc.
> would be completely crippled by such a requirement. If, and I think that
> is a big IF, we try to retain ESs then we would have to do much better
> than that.

I am being totally serious. I didn't state that every function in the
Library should have static throw added. IIRC, most functions in the Library
make no guarantees - only a very small minority promise much of anything. I
wouldn't want /any/ of these guarantees changed (well, except that all
destructors should guarantee not to throw anything, as should swap()).

What I was saying was that /IF/ a template function guarantees ---[today]---
that it only throws certain exceptions, then any function /IT/ calls should
make the same guarantee or better. I don't find this unreasonable in the
least - the Standard already places this requirement, ---[today]---. The
only difference if you used static ES would be that you get a compiler
warning instead of a call to unexpected() the first time you throw an
exception, which could very well be after you've delivered the software. I
would much prefer the compiler issue an error to tell me that an ES is being
violated.

I /do/ realize this would make a lot of existing non-ES-decorated code not
compile, and that it would force users to start adding ES. Perhaps there sh
ould be an option to make template static ES's active or not for backwards
compatibility (with the default being off for now).

For example:

typedef std::auto_ptr< MyClass > aptrMyClass;
/* uses normal ES semantics */

typedef __static_ES std::auto_ptr< MyClass > saptrMyClass;
/* uses static ES semantics - if ~MyClass doesn't promise static throw( ),
you get an error. */

If this option were available, I for one would use the static ES every
time - even though it would cause the tedium of having to fix /my code/ that
feeds into the STL.

Again, I'm not asking for /ANY/ new requirements to be placed on template
parameters - I'm asking for the requirement check to be shifted from
run-time to compile-time.

-- Early Ehlinger

David Abrahams

unread,
Dec 6, 2001, 2:40:58 AM12/6/01
to

"Mary K. Kuhner" <mkku...@kingman.genetics.washington.edu> wrote in message
news:9uh9ii$2kp2$1...@nntp6.u.washington.edu...

> There are certainly plenty of functions that must not throw *anything*.
> Destructors, to start with, and also some primitives like swap(), if you
> want exception safety elsewhere. Being able to assure yourself that
> your swap() cannot throw would be very nice.

Believe me, I'm aware of these things
(www.boost.org/more/generic_exception_safety.html) ;-)

> catch(...) is one way to accomplish this, but it's basically just saying
(if
> it absorbs the exception, and there's not much else it can do) "I declare
> unilaterally that the code below me *didn't* throw an exception." If
> the code below really did, and had reason to do so, frankly your program
> probably won't live long even if you don't call unexpected(). I see
> catch(...) as a form of defensive programming, and like all such, it can
hide
> (or worse, obfuscate) errors.

Yes, of course. When I discuss exception-specifications I usually forget to
mention the throws-nothing cases because I take their importance for
granted. In fact, some kind of strict checking for empty ESes might be a
very good thing... or at least, the warning tool you brought up earlier
would.

The distinction between the basic, strong, and nothrow guarantees is a
fundamental one to exception-safety. The distinction between "throws X or Y"
and "throws X, Y, or Z" is not. Useful distinctions are stark.

-Dave

apm

unread,
Dec 6, 2001, 2:48:29 AM12/6/01
to
bel...@pacbell.net (Bob Bell) wrote in message
news:<c87c1cfb.01120...@posting.google.com>...

> > Perhaps there has been too much emphasis on determining the type of an
> > exception. After all, when a function returns an integer error code we
> > do not bother saying what every possible error code value is for the
> > return value. The programmer has to read the documentation to figure
> > out what errors there might be.
>
> Because of the equivalence between different error reporting methods,
> I find reasoning about error codes and exceptions to be quite similar.

So do I, thanks to the discussions on this thread.

> If it is valid to state that a programmer must read the documentation
> to find out what error codes a function might return, then is it not
> also valid to state that a programmer must read the documentation to
> find out what exceptions a function might throw?

Up to a point. But when the programmer reads the documentation on the
error codes they at least can rely on the fact that the error code
will always be an integer. The trouble with exceptions is that they
are caught by type which means you need to know what the type is,
otherwise you cannot catch it.

> I see no reason to abandon different exception types. Remember, very
> few functions will even care that an exception is thrown; most
> functions will simply allow exceptions to pass through them silently,
> calling destructors along the way.

For those functions that don't care about the type it doesn't matter.
But for those that do it is important that the type can be determined.

> > The application's only use of ESs would be an empty ES on every dtor.
>
> It appears to me that this is the only good use of exception
> specifications -- marking functions that won't throw, which are
> destructors and other special functions like swap.

When this thread is finished this will probably be the one thing that
is agreed on. :-)

> > If I had to live without strong ES checking then with the
> > exception (groan...) of dtors I would not use ESs and would not have
> > have an exception hierarchy either.
>
> This strikes me as throwing the baby out with the bathwater. Just
> because exception specifications are not very useful does not demand
> or even imply that different exception types should be avoided.
>
> Bob Bell

It certainly does not *demand* it, I agree. However, it is my
preference to avoid throwing exceptions of different types if there is
no reliable way to get at the type afterwards. I would not form a
hard-and-fast rule about this. I would just point out that if
developers create an application exception hierarchy the mechanism of
ESs is insufficient for informing developers about what might be
thrown; they will have to use documentation instead. An alternative is
to just have one application exception class which has an 'etype'
member/accessor for those parts of the application that need to know
what kind of exception was thrown. Documentation is still needed I
agree so that the developer can consider what to do about all the
values that 'etype' might take. But the developer no longer has to
worry about unexpected program termination due to ES violation.


Regards,

Andrew M.

Early Ehlinger

unread,
Dec 6, 2001, 2:49:43 AM12/6/01
to
[Sorry if I've already responded to this - I've been working myself to
the bone and can't recall if I sent a draft of my thoughts that I
wrote yesterday morning... I can't seem to find them in my outbox,
but I may have sent them from a different computer. The gist of my
comments is the same, but the wording is undoubtedly entirely
different - Early]

"Francis Glassborow" <francis.g...@ntlworld.com> wrote


> Early Ehlinger <ear...@yahoo.com> writes
> >In fact, this could be a very simple solution to the static-check
ES vs.
> >templates problem. If a template calls a function which throws
something
> >outside of the template's static ES, then the compiler issues an
error - in
> >other words, the template's static ES is not only a promise to the
> >template's caller, but a requirement placed upon the code it uses
as well.
> >It is not outside the realm of C++ experience for the template to
place
> >requirements on the template parameters - in fact the Standard is
riddled
> >with such requirements.
>
> Are you being serious? Templates such as the containers, auto_ptr
etc.
> would be completely crippled by such a requirement.

Yes, I'm being completely serious, /and/ I disagree that the
containers, auto_ptr, etc., would be completely crippled by such a
requirement.

The containers have no ES's to be found in the Standard, so I fail to
see how changing ES's to statically check their template parameters
would change anything from today - it would be a no-op.

auto_ptr is a different story, because it does use ES extensively.
Every member has throw(). Only two of the members, however, place any
requirement on its template parameter. These requirements exist
today:

// 20.4.5:
namespace std {
template<class X> class auto_ptr {
template <class Y> struct auto_ptr_ref {};
public:
typedef X element_type;
// 20.4.5.1 construct/copy/destroy:
explicit auto_ptr(X* p =0) throw();
auto_ptr(auto_ptr&) throw();
template<class Y> auto_ptr(auto_ptr<Y>&) throw();
auto_ptr& operator=(auto_ptr&) throw();
template<class Y> auto_ptr& operator=(auto_ptr<Y>&) throw();
~auto_ptr() throw(); /* <- REQUIREMENT IMPLIED HERE!!!! */
// 20.4.5.2 members:
X& operator*() const throw();
X* operator->() const throw();
X* get() const throw();
X* release() throw();
void reset(X* p =0) throw(); /* <- REQUIREMENT IMPLIED
HERE!!!! */
// 20.4.5.3 conversions:
auto_ptr(auto_ptr_ref<X>) throw();
template<class Y> operator auto_ptr_ref<Y>() throw();
template<class Y> operator auto_ptr<Y>() throw();
};
}

auto_ptr implicitly places a requirement that X::~X() cannot throw.
This requirement is here with or without statically-checked ES. It is
obviously present as indicated by the fact that reset() and
~auto_ptr() both have a throw() ES. If X::~X() throws, then you will
get unexpected() and a nasty crash.

This restriction exists - today, and will continue to exist until the
Standard is changed to remove the throw() specification from
~auto_ptr() and reset().

I was merely arguing that if the Standard places this restriction on
the user's code, then it is reasonable to desire that the user's code
will be checked for a violation of said restriction. This check
exists today, but I believe we can do better than the current form of
crashing the program - I believe we can require

What is lacking is the compiler's help in guaranteeing that X::~X
/does not/ throw - this should be an easy thing for the compiler to
verify - simply check that X::~X() also has a throw(). Would this
"cripple" auto_ptr's usefulness? I think it depends on your
definition of useful. I would argue that such a check makes auto_ptr
even more useful by providing yet another level of safety - not only
will your object be deleted in the face of an exception, but you know
that your object won't cause a call to unexpected().

I can see where it would be a pain in the *** to change a bunch of
legacy code to add the throw() specification to the destructor (even
though this should probably be done anyway, due to the dangers that
throwing from a destructor generally involve). Perhaps a
middle-ground could be found whereby you must turn on the static
checking for a template:

typedef static throw auto_ptr< my_class > aptr_my_class; /* provides
the check I described above. */
vs.
typedef auto_ptr< my_class > aptr_my_class; /* works just as it does
today. */

> If, and I think
that
> is a big IF, we try to retain ESs then we would have to do much
better
> than that.

I agree that we could do better, and have begged for something better
in a number of other postings. E.g., it would be better, IMHO, to
have a mechanism to have a templatized ES that "bubbles up" the ES
from the template-parameter-class:

template<class T, class Allocator = allocator<T> >
class funky_container
{
void push_back(const T& x)
throw< Allocator::allocate , T::T , T::operator= >;
/* throws anything that the following member functions can
throw:
Allocator::allocate // any overloaded form
T::T // any overloaded form
T::operator= // any overloaded form */

void operator=( vector<T,Allocator> const& rhs )
throw< Allocator , T , std::bad_alloc >;
/* throws anything that any member of the classes T and
Allocator
can throw, in addition to std::bad_alloc */
};

If the guys at Comeau are reading this, would such a syntax totally
destroy your upcoming implementation of "export?"

-- Early Ehlinger

P.S. - I got curious and decided to check STLPort 4.5, MinGW 1.1,
Visual C++ 6.0 SP5, and Borland C++ Builder 5's implementations of
auto_ptr - the following chart illustrates my findings:

Implementation | Includes required throw() specification
--------------------------------------------------------
STLPort No
Visual C++ No
MinGW Yes
CBuilder Yes
--------------------------------------------------------

For STLPort and Visual C++ to not include the throw() clause may seem
like a minor issue - after all, if the class throws an exception in
its d'tor, it's probably a bug anyway, right? Well, that argument
notwithstanding, it is a scenario that leads to completely defined, if
draconian behavior. Such classes /should/ cause unexpected()

The Standard explicitly states that an implementation may "have an


explicit exception-specification that lists fewer exceptions than
those specified in this International Standard. It may not, however,

change the types of exceptions listed in the exception-specficiation
from those specified, nor add others." By not having ES at all, they
are effectively changing the ES to throw(...) and thus adding /all
types/ to the ES for ~auto-ptr.

With any luck, somebody from Microsoft and a contributor to STLPort
will read this and make sure their implementations are fixed in the
next release.

Terje Slettebø

unread,
Dec 6, 2001, 6:11:32 PM12/6/01
to
"David Abrahams" <david.a...@rcn.com> wrote in message news:<9ueudj$er7$1...@bob.news.rcn.net>...

> "apm" <ap...@student.open.ac.uk> wrote in message
> news:d1a33011.01120...@posting.google.com...
> > "David Abrahams" <david.a...@rcn.com> wrote in message
> news:<9uborv$kdi$1...@bob.news.rcn.net>...
>
>he is trying to get the committee to "just come out and
> tell users that they're not allowed to throw from destructors, and be done
> with it", since there are so many ugly effects associated with throwing
> destructors. Presumably, as an educator, he tends to prefer that he can give
> people a simple rule that is enshrined by the C++ standard, than to explain
> an ugly (but legal) morasse.

Do you mean to say that there can be cases where allowing exceptions
to leave destructors, can be useful?

If so, how?

Doesn't exceptions leaving destructors create havoc for making classes
exception-safe? (Which is why they don't let exceptions leave
destructors, in the standard library.)


Regards,

Terje Slettebo

Early Ehlinger

unread,
Dec 6, 2001, 6:21:26 PM12/6/01
to

"apm" <ap...@student.open.ac.uk> wrote in message
news:d1a33011.01120...@posting.google.com...

> bel...@pacbell.net (Bob Bell) wrote in message
> It certainly does not *demand* it, I agree. However, it is my
> preference to avoid throwing exceptions of different types if there
is
> no reliable way to get at the type afterwards. I would not form a
> hard-and-fast rule about this. I would just point out that if
> developers create an application exception hierarchy the mechanism
of
> ESs is insufficient for informing developers about what might be
> thrown; they will have to use documentation instead. An alternative
is
> to just have one application exception class which has an 'etype'
> member/accessor for those parts of the application that need to know
> what kind of exception was thrown. Documentation is still needed I
> agree so that the developer can consider what to do about all the
> values that 'etype' might take. But the developer no longer has to
> worry about unexpected program termination due to ES violation.

I'm not sure that an etype member is actually of any benefit:

enum e_t{ e1_ , e2_ , e3_ };
class e { public: virtual e_t etype() = 0; };
class e1 : public e { public: e_t etype() { return e1_; } };
class e2 : public e { public: e_t etype() { return e2_; } };
class e3 : public e { public: e_t etype() { return e3_; } };

void f1() throw( e1 , e2 , e3 );

void f2()
{
try { f1(); }
catch( e1& e )
{ ... }
catch( e2& e )
{ ... }
catch( e3& e )
{ ... }
}

void f3()
{
try { f1(); }
catch( e& the_e )
{
switch( the_e.etype() )
{
case e1_: ...
case e2_: ...
case e3_: ...
}
}
}

The only possible benefit I can think of is that with the switch
you might be able to group your exceptions independent of the
exception hierarchy:

void f4()
{
try { f1(); }
catch( e& the_e )
{
switch( the_e.etype() )
{
case e1_: /* fall through */
case e2_:
/* handle e1_ & e2_ identically */
break;
case e3_:
/* but handle e3_ differently */
}
}
}

-- Early Ehlinger

Terje Slettebø

unread,
Dec 6, 2001, 6:24:10 PM12/6/01
to
"David Abrahams" <david.a...@rcn.com> wrote in message news:<9udu9q$n1b$1...@bob.news.rcn.net>...
> "Terje Slettebø" <tsle...@acm.org> wrote in message

> news:C9fO7.5523$Sa4.6...@news01.chello.no...
> > "David Abrahams" <david.a...@rcn.com> wrote in message
>
> > > What's wrong with writing "boy scout" functions, that are prepared for
> > > anything? It isn't that hard to do.
> >
> > As it has been pointed out by others, here, exceptions is just one way of
> > signalling error conditions, or other signals. If you think exceptions
> > shouldn't be documented, in the documentation, don't you think return
> codes
> > should be documented, either?
>
> I can't make sense of the second part of that last sentence, but its premise
> is false. I do think exceptions should be documented in the documentation.

I meant if you thought error codes shouldn't be documented, if you
thought exceptions shouldn't be documented. But since that's not the
case, then we agree.


> > The issue here isn't whether or not exceptions should be documented, but
> > whether or not one should use throw-clauses as a documentation.
>
> I think you really mean "exception specifications", not "throw-clauses".

Isn't that the same thing?

I thought throw-clauses was the "throw(...)" part of the function
signature, in other words, ES.


> > However, the way you answered, seemed to indicate that the calling
> function
> > didn't need to know anything about what may happen (regardless of whether
> > it's documented using throws-clauses, or not), so that's what I answered
> to,
> > now.
>
> That is true of 99.9% of all functions, in my experience. Very few of them
> actually do need to know anything about what may happen.

Then how can it e.g. catch an exception by type, using try-catch?


> As I understand it, you want enforced exception
> specifications so that you can be sure that every function knows everything
> that might be thrown at it. Have I misunderstood something?

That's what static checking of ES is about, yes. I haven't said I want
this. I've just said that if one use ES, than static checking could be
useful, so one is guaranteed that unexpected() won't be called.



> > If using exception specifications, an unspecified exception can result in
> a
> > call to terminate(), which calls abort(), without letting any possible
> outer
> > handler take care of it, not even a catch-all handler.
> >
> > Since we are talking about exception specifications, this is what I
> referred
> > to as "the current situation."
> >
> > Given that, can you now understand why I said that almost anything can
> > improve those exception specifications?
>
> Ah, yes. But a useless feature (and I'm not saying ESes are useless, but
> that's another discussion) doesn't neccessarily need to be improved: it can
> simply be avoided.

I understand what you mean.

Well, as others have pointed out, the more fundamental notions of
exception safety (basic, strong and nothrow guarantees) are really
more important than this, since it enables you to avoid resource
leakage.

As to what use enforced ES (static or dynamic checking), in general,
have, well. I guess it's more of documenting what may be thrown, so
that calling functions know what to expect (or if they can throw at
all).

This way, you get a warning if the function doesn't handle it, or
specify it, itself. However, this may lead to a lot of ES, as you also
point out.


> So I am still unconvinced that there's a problem... other
> than that people are perennially attracted to ESes because they don't really
> understand what they do.

:)

I guess, since they are in the standard, people are trying hard to
find out why. :)

Similar to that compiler vendors is trying hard to be able to
implement "export."


> > But why do you think exception specifications were made, in the first
> place?
>
> I don't know. I have spoken with Bjarne Stroustrup about this personally,
> and never got a rationale that I found convincing. What he said, as I
> remember it, was something along the lines of: "some code may want to rely
> on the fact that it will only see a limited range of exception types". That
> argument doesn't seem to stand up for most applications, since the price
> paid for that knowledge is termination.

I agree. :)

"We may tell you, but then we have to kill you." ("Sneakers")


> ...and I suppose you spoke with the original proposer of the feature to get
> this rationale? ;-)

No, I just made it up. :)

Seriously, though, this is how I've understood it. On the other hand,
if exceptions aren't caught, the program terminates anyway, with or
without ES. So, in a way, exceptions are always caught.


> > They are actually very useful.
> >
> > If, for example, you know that a function can throw an IOException, then
> the
> > calling function can know that, and can catch that particular exception,
> and
> > do something meaningful about it (including giving an error-message).
>
> That isn't an example of using an exception specification. That's an example
> of using some knowledge about what exceptions may be thrown into a function.

Yes, I was arguing for documented exceptions (being documented with
ES, in this case. This doesn't have to be the case, thought.) But,
since that's not what you meant, then that's something else.


> I know it sounds like I'm picking nits with your argument, but please bear
> with me.

No, you don't. :) I understand. It seems we've just talked past each
other, a little.

The difficulty in this thread is that there are multiple issues, both
whether or not exceptions should be documented (APM suggested earlier
they shouldn't be documented, but changed that later), and whether or
not ES is useful, if they should be enforced statically or
dynamically. So it's not always easy to understand what is being
discussed at a particular point.


> An example of using an exception specification is a programming
> scenario where the language feature comes into play. So, let's look at where
> an enforced specification might come into play:
>
> 1. You re-implement a function to make it multithread-safe. This function is
> at the core of your system, e.g. in std::allocator. Now it needs to acquire
> a mutex which it didn't need before. The system only has a limited number of
> mutexes; if you can't get the mutex you throw an exception. So, you add
> no_more_mutexes to the function's exception specification. How many other
> functions need to change in order to make the compiler happy? How many
> functions actually care about the new exception? Is it worth it?

Good question.

That's an example which would require almost every function to have
the ES (like arithmetic exceptions, too, such as division by zero.)

Anyway, ES is often not implemented, either (like in VC++ and Intel
C++).


> 2. You write a new function which is supposed to report all errors thrown at
> it. You give it an exception-specification of throw(), and you're careful to
> leave out any catch(...) clause. OK, now this function can't call any other
> functions with a throw(...)/missing ES, because that would be a violation.
> Every exception that can be thrown at the function must be matched by a
> corresponding catch clause. Let's look at the impact on the rest of the
> program. To be useful, every function in a call chain from this catch-all
> function must have the narrowest possible exception-specification, or you
> will end up having to catch broad categories of exceptions. Any time a
> function anywhere wants to report a new kind of error, that error must be
> propagated back up the chain in ESes to each such catch-all function. Oh,
> you say that we can handle that problem by defining exception hierarchies,
> and throwing classes derived from some base exception? Careful: the
> enforcement you thought you had bought by maintaining all those ESes is now
> undermined, because the derived classes contain information about what went
> wrong that's unavailable to the reporting function unless it has catch
> clauses for each derived class... but the ESes won't enforce that.

You bring up valid points.

I haven't said enforced ES (statically or dynamically enforcing) would
be better than no ES. As mentioned, I've only said that such static
enforcing, could be better than dynamic enforcing, if ES is being
used.

Apart from this, I've just argued for documented exceptions (just like
documented error codes), and that they may be regarded as part of the
contract, this way. But we agree here, too. This is so that a calling
function may know what it may expect.


> > Without that, it will be no way to do anything meaningful about it, like I
> > said above, you can't even get the name of the exception, if you don't
> know
> > the type.
> >
> > This is also why exception specifications exists in Java, and are
> statically
> > checked (at compile-time), there. This ensures that all exceptions are
> > caught, and there's no risk for any unexpected() call, since that is not
> > used.
>
> Except for the special category of unchecked exceptions that had to be
> created precisely because strict checking caused such a maintenance
> nightmare.

Yes, I know. :)


> > Besides, using static checking, means the exception specifications there
> > have zero run-time overhead, unlike the C++ exception specifications.
>
> That's incorrect: a good C++ compiler does not incur any runtime overhead
> for an exception specification (unless an exception is thrown - Java is also
> subject to this caveat).

Are you certain about this?

I read about this in Scott Meyers' "Effective C++"-books (in an item
about ES).

I agree with you that the use of exceptions, in a program, hardly
recurs any overhead (because it can be coded very efficiently, as long
as no exception is thrown). What I'm talking about is ES.

How can a compiler enforce ES, without run-time overhead?

For example, if a function deep down a call-chain throws an exception,
then during stack unwinding, it arrives at a function that has ES.
Here, it must match the exception against the ES, and if not found,
call unexpected(). At least, that's what I thought would have to be
done (and also since run-time overhead is mentioned in the mentioned
book).

But maybe compilers can optimize this away, as well.


> In fact, a good C++ compiler can use
> exception-specifications to reduce the overall amount of generated code,
> which sometimes improves runtime speed.

Or bring the program to a grinding halt, with a call to unexpected().
:)


Regards,

Terje Slettebo

David Abrahams

unread,
Dec 6, 2001, 11:02:41 PM12/6/01
to

"Early Ehlinger" <spam...@spamblaster.org> wrote in message
news:p3xP7.91715$lV4.11...@e420r-atl1.usenetserver.com...

> "David Abrahams" <david.a...@rcn.com> wrote in message
> news:9uh13t$4rp$1...@bob.news.rcn.net...
> > > The Standard specifically disallows adding exceptions to the ES of
> > > any Standard Library component (e.g., std::allocator).
> >
> > Not so for standard library writers: they are allowed to add
> > arbitrary implementation-defined exceptions.
>
> Not true! Again, the Standard specifically disallows adding
> exceptions to the ES of any Standard Library component -
> See Section 17.4.4.8, footnote 175:
>
> | 175) That is, an implementation of the function will have an
> | explicit exception-specification that lists fewer
> | exceptions than those specified in this International
> | Standard. It may not, however, change the types of
> | exceptions listed in the exception-specification from those
> | specified, add others.

Thanks, I'm getting forgetful. I was thinking of this:

17.4.4.8 Restrictions on exception handling
3 No destructor operation defined in the C++ Standard Library will
throw an exception. Any other functions defined in the C++ Standard
Library that do not have an exception-specification may throw
implementation-defined exceptions unless otherwise specified.

But of course that doesn't say what I claimed.

> > But anyway, the point stands because you
> > probably have other functions at the core of your system on which
> > the standard places no restriction at all.
>
> The standard often does place restrictions on functions at the
> core of your system (albeit sometimes implicitly). For example,
> because ~auto_ptr() is declared with throw(), you are restricted
> from throwing in the destructor of any class managed by auto_ptr<>.

<pedantry>
That's actually not why you're restricted from throwing from your own
destructor. That alone would produce entirely predictable behavior
(termination).

The restriction comes from 17.4.3.6:

Other functions
1 In certain cases (replacement functions, handler functions,
operations on types used to instantiate standard library template
components), the C++ Standard Library depends on components supplied
by a C++ program. If these components do not meet their requirements,
the Standard places no requirements on the implementation.

2 In particular, the effects are undefined in the following cases:
...
--- if any replacement function or handler function or destructor
operation throws an exception, unless specifically allowed in the
applicable Required behavior paragraph.


In fact, the presence of a throw() specification in the standard (the only
kind that's in there) means nothing about whether an exception specification
is actually present. That's because none of those functions are virtual and
none call any user-supplied functions which are allowed to throw. So an
exception-specification is undetectable and not required under the as-if
rule.
</pedantry>


> > Then everyone would derive their exception classes from
> > std::exception (I presume that would be in the standard
> > library function's ES) to get around the compiler and
> > the checks would be useless.
>
> People could use the same argument against having explicit
> types; everybody'll just reinterpret_cast everything and
> type-checking would be useless. If a facility for safety
> is introduced, wise developers will not abuse it.

I certainly would. There are some things which aren't best done with static
checks and this is one of them. The exception-handling mechanism is built
around RTTI and dynamic type information. It provides the tools to achieve
run-time safety, much like your favorite dynamic language (I'm assuming you
have one).


> > Exactly. So, my point is that the ripple effect has an extremely
> > high cost for code maintenance, while the feature causing the ripple
> > effect has comparatively few benefits in practice.
>
> There is only a ripple effect if 1 of 2 things occurs:
>
> 1) there is no mechanism for "inheriting" ES from called functions,
> or for "bubbling up" ES, thus allowing intermediate functions
> the luxury of not knowing what exceptions pass through them
> while at the same time telling their callers what to expect.

Separate compilation pretty much guarantees this. You can't really achieve
that bubbling without tying together interface and implementation.

> 2) you change an interface to an existing function by modifying its
> ES.
>
> The former case is the cause of a lot of grief in the Java world, or
> so I'm told, and I think that as we strive to improve ES in the C++
> world, we should find a mechanism that nullifies this possibility.
> I have offered up templatized ES as a possible solution, but I'm sure
> somebody will have something better.

I doubt a solution is possible. Don't forget that in most programs, there
are still a lot of functions which aren't templates.

> The latter case is something which the Language cannot help with,
> any more than if you change the parameter list to an existing
> function. (Well, assuming that you're using ES at all :)

Yes, but as I've heard said, proof by analogy is fraud. There is little
similarity between the effects of mismatching a parameter list in a caller
and callee and the effects of throwing an exception which isn't declared to
the caller.

> I don't think static ES would have "few benefits" - it would provide a
> mechanism similarly to const; an optional means of codifying the
> semantics of your application.

Another bad analogy. Constness is a fundamental property of an operation
which is unlikely to change, but the set of ways in which an operation is
likely to fail could change often (unless it is a nothrow operation). Also,
it is typical that the callers of a const operation care that it is const.
It might even affect whether the program crashes, since const objects can be
allocated in read-only memory. On the other hand the callers of a function
typically don't care what exceptions it can throw. If they do, maybe a
different error reporting mechanism would be more appropriate. Exceptions
are best at long-distance error reporting.

> Consider:
> class const_fu
> {
> public:
> void checksomething() const;
> void dosomething();
> void example() const
> {
> checksomething(); // OK - checksomething is as const as I am.
> dosomething(); // ERROR - dosomething is less const than I am.
> }
> };
>
> class throw_fu
> {
> public:
> void checksomething() static throw();
> void dosomething();
> void example() static throw()
> {
> checksomething(); /* OK - checksomething is as
> throw-restrictive as
> I am. */
> dosomething(); /* ERROR - dosomething is less
> throw-restrictive than
> I am. */
> }
> };

I've said elsewhere that I don't have a problem with static throw() -- nice
syntax, BTW, another overload for "static" ;-) -- (although I have some
doubts about whether it will play nicely with existing code). What I object
to is "static throw(x)" or "static throw(x,y)".

> const has a ripple effect as well if you don't have it in place from
> the
> get-go. If you attempt to "go back and const-ify" a class, you
> quickly
> discover that making one function const can have unintended
> consequences
> and you end up having to write const-overloads, change other functions
> to
> be const, etc.

The nature of const-ripple is completely different. It is extremely rare to
loosen the constness of an operation. It is much more common to change the
set of errors that can be reported.

> Do you think these burdens of const-correctness outweigh its
> usefulness, too?

No.

apm

unread,
Dec 6, 2001, 11:05:27 PM12/6/01
to
Francis Glassborow <francis.g...@ntlworld.com> wrote in message
news:<jqWi$FDVkP...@robinton.ntlworld.com>...

> In article <d1a33011.01120...@posting.google.com>, apm
> <ap...@student.open.ac.uk> writes
> >Perhaps there has been too much emphasis on determining the type of an
> >exception. After all, when a function returns an integer error code we
> >do not bother saying what every possible error code value is for the
> >return value. The programmer has to read the documentation to figure
> >out what errors there might be.
>
> Perhaps an idea from another thread might be appropriate. If we enhanced
> catch(...) with a method by which the exception type can be reported (at
> the same time improve typeid to provide recognisable names) then
> programmers would have an easier tool for determining what unexpected
> exception had been propagated.

That sounds like a good idea to me because it solves the problem of
how do we get at the type of the exception, especially when it is
distant parts of the app that both need access to the type. Passing it
along every stage of the call chain is a pain that most of us would
like to avoid.

However, this relies on typeid being able to provide a recognisable
name which is something else that has been campaigned about for a
while with about the same level of success as strong ES checking.

I think the trouble is that by and large, the strong type checking
that exists in C++ does so not in order to force correct programming
but for technical reasons connected with implementing other facilities
offered by C++. For example, function overloading uses the type
information in each argument to mangle the name so that the linker can
distinguish between multiple instances of the same function name.
Discussions about type where the strong typing argument is accepted
tend to be because of concerns about linker issues. Const is an
exception to this. Const is obviously to do with const-correctness.
But in general, C++ does not want to force people to program in the
correct way, it takes the view that the programmer is always right. My
proposal was always OPTIONAL, only programmers that wanted to use ESs
would find onlythrow useful. Similarly, const is optional so not
everyone uses it. I thought that by making it optional there would be
little objection to the proposal, given that we all seem to agree that
the current form of ES is sub-optimal.

I have now given up on the proposal. It never occurred to me that
developers that acknowledged the deficiencies in the current form of
ESs would not want to see them fixed. I was warned that some committee
members were/are against strong/static ES checking but was not
prepared for encountering objections at this early stage. In a way it
is good that the feeling against onlythrow has emerged at this point.
It saves me the trouble of chasing it.

Before we close this chapter on strong ES checking I would like to see
the arguments against fixing the ES mechanism collected in one place.
So far I am not sure what the argument actually is. I know my proposal
contained holes (how to painlessly pass the promise up the call-chain,
how to work with templates etc) but that is not what I am talking
about. What I mean is "given that the current form of ES is broken,
why should it NOT be fixed?". As far as I can see, the argument at the
moment merely says "because it wouldn't add anything". I don't
consider that to be a good argument. For one thing, if it's true then
by the same reasoning ESs should not be part of the language and
should be dropped at some point.

Regards,

Andrew M.

David Abrahams

unread,
Dec 7, 2001, 7:13:46 AM12/7/01
to

"Terje Slettebø" <Terje.S...@iu.hio.no> wrote in message
news:6de16cfb.01120...@posting.google.com...

> "David Abrahams" <david.a...@rcn.com> wrote in message
news:<9udu9q$n1b$1...@bob.news.rcn.net>...

>


> > > The issue here isn't whether or not exceptions should be documented,
but
> > > whether or not one should use throw-clauses as a documentation.
> >
> > I think you really mean "exception specifications", not "throw-clauses".
>
> Isn't that the same thing?
>
> I thought throw-clauses was the "throw(...)" part of the function
> signature, in other words, ES.

There's actually no such thing as a "throw-clause". The standard defines
"throw-expression" and "exception specification". "Throw-clause" sounds a
lot more like the former.

> > > However, the way you answered, seemed to indicate that the calling
> > function
> > > didn't need to know anything about what may happen (regardless of
whether
> > > it's documented using throws-clauses, or not), so that's what I
answered
> > to,
> > > now.
> >
> > That is true of 99.9% of all functions, in my experience. Very few of
them
> > actually do need to know anything about what may happen.
>
> Then how can it e.g. catch an exception by type, using try-catch?

If it knows nothing about the possible exceptions, then of course it can't.
My point is that only a very few functions in a program need to do that, or
ought to.

> Well, as others have pointed out, the more fundamental notions of
> exception safety (basic, strong and nothrow guarantees) are really
> more important than this, since it enables you to avoid resource
> leakage.

Much more important than resource leakage, they enable you to reason about
the behavior and invariants of your system in the face of errors
(www.boost.org/more/generic_exception_safety.html)

> I guess, since they are in the standard, people are trying hard to
> find out why. :)

They do have uses. They enable certain (space, on a good compiler)
optimizations, when used carefully and uniformly. They can be used as part
of a mechanism to translate exception types, though I don't think this is a
very good use of ESes.

> > > But why do you think exception specifications were made, in the first
> > place?
> >
> > I don't know. I have spoken with Bjarne Stroustrup about this
personally,
> > and never got a rationale that I found convincing. What he said, as I
> > remember it, was something along the lines of: "some code may want to
rely
> > on the fact that it will only see a limited range of exception types".
That
> > argument doesn't seem to stand up for most applications, since the price
> > paid for that knowledge is termination.
>
> I agree. :)
>
> "We may tell you, but then we have to kill you." ("Sneakers")

:-)

> > ...and I suppose you spoke with the original proposer of the feature to
get
> > this rationale? ;-)
>
> No, I just made it up. :)
>
> Seriously, though, this is how I've understood it. On the other hand,
> if exceptions aren't caught, the program terminates anyway, with or
> without ES. So, in a way, exceptions are always caught.

Yes, but if you think of an ES as a kind of assertion, you can see that
catch(...) potentially prevents you from seeing the problem unless you have
an ES there to trap it at an inner level.

> > > Besides, using static checking, means the exception specifications
there
> > > have zero run-time overhead, unlike the C++ exception specifications.
> >
> > That's incorrect: a good C++ compiler does not incur any runtime
overhead
> > for an exception specification (unless an exception is thrown - Java is
also
> > subject to this caveat).
>
> Are you certain about this?

Yes.

> I read about this in Scott Meyers' "Effective C++"-books (in an item
> about ES).

If he wrote that an ES neccessarily causes slowdown, he was wrong. Did he
really say that?
A compiler can implement a try/catch block without incurring any runtime
overhead unless an exception is thrown. An ES is almost exactly like a
try/catch block. If e1...en are listed in the ES, then it's almost
equivalent to this:

try {
// function body
}
catch(e1&) { throw; }
catch(e2&) { throw; }
...
catch(...) { unexpected(); }

> I agree with you that the use of exceptions, in a program, hardly
> recurs any overhead (because it can be coded very efficiently, as long
> as no exception is thrown).

It could even speed things up over other error-handling methods.

> What I'm talking about is ES.
>
> How can a compiler enforce ES, without run-time overhead?

I think my example above should say enough.

> For example, if a function deep down a call-chain throws an exception,
> then during stack unwinding, it arrives at a function that has ES.
> Here, it must match the exception against the ES, and if not found,
> call unexpected(). At least, that's what I thought would have to be
> done (and also since run-time overhead is mentioned in the mentioned
> book).
>
> But maybe compilers can optimize this away, as well.

Unless the exception is actually thrown.

> > In fact, a good C++ compiler can use
> > exception-specifications to reduce the overall amount of generated code,
> > which sometimes improves runtime speed.
>
> Or bring the program to a grinding halt, with a call to unexpected().
> :)

You don't like to live dangerously? ;-)

Francis Glassborow

unread,
Dec 7, 2001, 7:46:39 AM12/7/01
to
>I have now given up on the proposal. It never occurred to me that
>developers that acknowledged the deficiencies in the current form of
>ESs would not want to see them fixed. I was warned that some committee
>members were/are against strong/static ES checking but was not
>prepared for encountering objections at this early stage. In a way it
>is good that the feeling against onlythrow has emerged at this point.
>It saves me the trouble of chasing it.

Largely at this stage you will hear explicit statements from those that
are strongly against ES in any form. Many other Committee members who
may be less dogmatic on the subject will not express support for fixing
them until they are reasonably convinced that a fix can be achieved.


--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Francis Glassborow

unread,
Dec 7, 2001, 7:47:35 AM12/7/01
to
In article <9ummkb$a1u$1...@bob.news.rcn.net>, David Abrahams
<david.a...@rcn.com> writes

>The nature of const-ripple is completely different. It is extremely rare to
>loosen the constness of an operation. It is much more common to change the
>set of errors that can be reported.

It strikes me that the better analogy is between const correctness and
throw() correctness. I think that requiring that the latter be
statically enforced might show similar benefits to requiring that const
be statically enforced. In the short term we would have much the same
problem that we encountered when const correctness became required, but
in the long term there might be some real benefits.

If I were being radical I might suggest that all extern "C" functions
should automatically have throw() semantics.


--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Francis Glassborow

unread,
Dec 7, 2001, 7:48:22 AM12/7/01
to
In article <p3xP7.91715$lV4.11...@e420r-atl1.usenetserver.com>, Early
Ehlinger <spam...@spamblaster.org> writes

>> Not so for standard library writers: they are allowed to add
>> arbitrary implementation-defined exceptions.
>
>Not true! Again, the Standard specifically disallows adding
>exceptions to the ES of any Standard Library component -
>See Section 17.4.4.8, footnote 175:


Read his words. He wrote 'exceptions' NOT 'exception specifications'.

--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Francis Glassborow

unread,
Dec 7, 2001, 7:48:53 AM12/7/01
to
In article <vi4P7.39934$py4.23...@news2.nash1.tn.home.com>, Early
Ehlinger <ear...@yahoo.com> writes

>Again, I'm not asking for /ANY/ new requirements to be placed on template
>parameters - I'm asking for the requirement check to be shifted from
>run-time to compile-time.

And you entirely miss the point. Any function that declares any instance
of a Standard Library template must either have a catch(...) wrapped
round it
or have a no exception specification. The same applies to any function
that calls such a function etc.

The result is that in the presence of standard library templates your
code becomes effectively uncheckable. Nor should you assume that the
full source code for templates will always be available, some library
vendors are actively researching the possibility of shipping template
libraries in a semi-compiled form.


--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Jani Kajala

unread,
Dec 7, 2001, 1:25:14 PM12/7/01
to
"David Abrahams" <david.a...@rcn.com> wrote in message
news:9ummkb$a1u$1...@bob.news.rcn.net...

> There is little similarity between the effects of mismatching a
> parameter list in a caller and callee and the effects of throwing
> an exception which isn't declared to the caller.

I must disagree on this. If you don't know how the function can fail before you
write the function, then you haven't really designed it beforehand. And if you
frequently need to change functions which are used in many places then you are
*begging* for trouble, doesn't matter do you use ES or not. To be even remotely
sure that your changes don't affect any users you would need to go through and
re-test every user of the function anyway. Adding another exception to exception
specifications would be the *smallest* overhead which is caused by the changes.


Regards,
Jani Kajala

David Abrahams

unread,
Dec 7, 2001, 10:42:14 PM12/7/01
to

"Francis Glassborow" <francis.g...@ntlworld.com> wrote in message
news:6tHUuJDN...@robinton.ntlworld.com...

> In article <9ummkb$a1u$1...@bob.news.rcn.net>, David Abrahams
> <david.a...@rcn.com> writes
> >The nature of const-ripple is completely different. It is extremely rare
to
> >loosen the constness of an operation. It is much more common to change
the
> >set of errors that can be reported.
>
> It strikes me that the better analogy is between const correctness and
> throw() correctness. I think that requiring that the latter be
> statically enforced might show similar benefits to requiring that const
> be statically enforced. In the short term we would have much the same
> problem that we encountered when const correctness became required, but
> in the long term there might be some real benefits.

If ESes corresponded to a binary condition, I would almost agree with you
[remember that modifying a const object can unavoidably crash a program, but
you almost have to go out of your way to crash because you were expecting a
different exception type] but they don't.

David Abrahams

unread,
Dec 8, 2001, 9:15:28 AM12/8/01
to

"Jani Kajala" <ja...@REMOVETHIS.sumea.com> wrote in message
news:9uq743$vtp$1...@news1.song.fi...

> To be even remotely
> sure that your changes don't affect any users you would need to go through
and
> re-test every user of the function anyway.

That would rule out the maintenance of third-party libraries altogether.
Don't you get even a remote sense of confidence from a good set of unit
tests?

-Dave

Francis Glassborow

unread,
Dec 8, 2001, 1:44:21 PM12/8/01
to
In article <9uqvqe$ea4$1...@bob.news.rcn.net>, David Abrahams
<david.a...@rcn.com> writes

>> It strikes me that the better analogy is between const correctness and
>> throw() correctness. I think that requiring that the latter be
>> statically enforced might show similar benefits to requiring that const
>> be statically enforced. In the short term we would have much the same
>> problem that we encountered when const correctness became required, but
>> in the long term there might be some real benefits.
>
>If ESes corresponded to a binary condition, I would almost agree with you
>[remember that modifying a const object can unavoidably crash a program, but
>you almost have to go out of your way to crash because you were expecting a
>different exception type] but they don't.

Perhaps you misunderstood me (or vice-versa). Isn't throw(0 (i.e. this
function does not propagate any exceptions) a binary condition? Either
it is true or it is not. It does not matter what the type of an
exception is because we are saying that there are none.


--
Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

It is loading more messages.
0 new messages