From 8654582176436585139
X-Google-Thread: f78e5,82cd3599ce330676
X-Google-NewGroupId: yes
X-Google-Attributes: gid7894ca11fe,domainid0,public,usenet
X-Google-Language: ENGLISH,ASCII-7-bit
Path: g2news1.google.com!news1.google.com!npeer03.iad.highwinds-media.com!news.highwinds-media.com!feed-me.highwinds-media.com!Xl.tags.giganews.com!border1.nntp.dca.giganews.com!nntp.giganews.com!local2.nntp.dca.giganews.com!news.giganews.com.POSTED!not-for-mail
NNTP-Posting-Date: Mon, 05 Apr 2010 00:40:54 -0500
Return-Path: <cppmods@ruralroute.cs.rpi.edu>
To: (Usenet)
From: Herb Sutter <herb.sutter@gmail.com>
Newsgroups: comp.std.c++
Subject: Re: throwing in a noexcept(true) function
Organization: Forte Inc.  http://www.forteinc.com/apn/
Sender: cppmods@cs.rpi.edu
Approved: austern@google.com
Message-ID: <n3qhr5dd7vn0t8osocuk08edhgpo5k7jl8@4ax.com>
References: <4BB4D8B0.3070603@f2.dion.ne.jp>
 <4BB73613.2040903@f2.dion.ne.jp>
Content-Type: text/plain; charset=us-ascii
X-Original-Date: Sun, 04 Apr 2010 14:12:11 -0700
X-Submission-Address: std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
Date: Mon,  5 Apr 2010 00:36:14 CST
Lines: 243
X-Usenet-Provider: http://www.giganews.com
X-Trace: sv3-e7ww1HWeHmKNKMjwdqMIe0Xcq6nNhkx3DEe7fI+lq8aPushSvnZl/6xUiF3RtuhqhsVxu9VdSddYTDj!kk7Asv4LukHG+YfadUV3Z+SeJ9YoLBp1z+ca1YdNMfxHylLkUzJm/w5EyleDgznScf0G7P5h
X-Complaints-To: abuse@giganews.com
X-DMCA-Notifications: http://www.giganews.com/info/dmca.html
X-Abuse-and-DMCA-Info: Please be sure to forward a copy of ALL headers
X-Abuse-and-DMCA-Info: Otherwise we will be unable to process your complaint properly
X-Postfilter: 1.3.40
Xref: g2news1.google.com comp.std.c++:2372

On Sun,  4 Apr 2010 12:04:30 CST, Kazutoshi Satoda
<k_satoda@f2.dion.ne.jp> wrote:
>Herb Sutter wrote:
>>
>> The trouble with (d) is that then you get all the problems
>> Java gets with statically checked exceptions,
>
>I re-read some articles about what was wrong with checked exceptions.
>http://www.artima.com/intv/handcuffsP.html
>
http://googletesting.blogspot.com/2009/09/checked-exceptions-i-love-you-but-you.html
>For all problems written there, I thought they won't be problems with
>noexcept because noexcept is not the default and not written for
>specific types.

It's true that Yes/No is a much simpler subset of SetOfTypes/None. But
it's still the same principle. The question is whether the great
reduction of possibilities makes the problem tractable.

It seems to me that there are some fundamental things here:

 1. Static checking inherently defeats writing naturally
exception-neutral code which should be the default, because the
specifications have to be written explicitly to be useful (and this is
true whether the default is "throws nothing" or "throws anything").

 2. Static checking is intrusive and viral from the bottom up and has
to be explicitly written to be useful (again, whether the default is
"throws nothing" or "throws anything").

 3. Noexcept used "for correctness" is for only a very small set of
code, and its new use of "for performance" applies to general purpose
code but has to be very simple to write if it's to be used there.

Taking them in order:

Most code is supposed to be exception-neutral by design. The code
(below) that detects an error throw, the code (above) that can handle
an error catches, and the rest of the code is supposed to just stay
out of the way.

So the key problem inherent in any static checking is that it defeats
this model by being intrusive: For static checking to be useful it
requires all code to now declare and know under what circumstances
exceptions can be thrown through it (even if we don't require listing
the types of exceptions, as in Java). And it's not enough to say "in
C++ the default is 'throws something'" because that just means that
"in C++ the default is 'can't be called from a noexcept function'" if
we enforce static checking.

That's untenable in general, and it's why in Java most people quickly
end up with the useless-and-soul-destroying "throws Exception" that
defeats the purpose of checked exceptions in the first place and whose
moral equivalent here is the default nothrow(false). At least in C++
we'd devolve to the default which is easier to spell than "throws
Exception," but it still defeats the purpose of static checking. And
of course it's particularly hard in generic code (more on this below).

Static check would be viral from the bottom up because: a) you would
have to annotate all callees (or wrap those calls in a try/catch
whether or not it's really necessary) before you can annote your own
function; and b) you would have to annotate your own function before
it's usable from callers taht are annotated with noexcept.

Further, noexcept targets the (one) important case of "throws
nothing," but note that this is primarily for a very restricted set of
code -- notably destructors, deallocation functions, and swap, a very
small amount of code that offer the nothrow/nofail exception safety
guarantee for correctness in order to implement the "commit/rollback"
part of a function. In fact it's even stronger -- these functions have
to be guaranteed not to fail, not just not to throw, so that they can
be used as the building commit/rollback code that can reliably take
interim work that was done off to the side and either accept it as the
new state or else throw it away.

Now, granted, the current formulation of noexcept is intended to
expand that important case to a (to me secondary, but still
interesting and probably much more common) additional case of code
that wants to offer nothrow/nofail for optimization purposes. In
particular, unlike today's exception specifications, including even
throw(), noexcept allows optimization of the noexcept function's
callees (functions called by the noexcept function, for example to
assume those must be noexcept as well if they are not called within a
try/catch), not just its callers. This latter use is what I expect to
broaden the scope of the code that cares about nothrow, but it has to
be usable by a wide audience of programmers, which I don't think it is
if we follow what you write below.

So I see two uses: nothrow for correctness which applies to very
little code and so benefits little from static checking, and nothrow
for performance which to be useful has to be easily usable by general
C++ programmers and so requires near-seamless static checking which I
haven't seen practically proposed yet.

In that context:

>> that scheme doesn't work at all with templates (what exactly would you
>> write?)
>
>Like this:
>
> template <class T, class Allocator = allocator<T> >
> class vector {
>   ...
>   iterator erase(const_iterator position) noexcept(
>       has_nothrow_copy_constructor<T>::value &&
>       has_nothrow_move_constructor<T>::value &&
>       has_nothrow_copy_assign<T>::value &&
>       has_nothrow_move_assign<T>::value)

This seems problematic for several reasons, mostly on the grounds of
usability:

 - Usability: To me, this falls squarely into "the cure is worse than
the disease" territory. A few library writers may do this to gain some
potential performance (and they can do it whether we mandate static
checking or not!), but C++ programmers in general are just not going
to write this code (and mandating static checking would attempt to
make them do so). If the goal is to allow C++ programmers in general
to write "this doesn't throw" on a function in order to make it
faster, which I suspect is the goal for many, I don't think this meets
the bar.

 - Usability: Requiring static checking means you couldn't
instantiate vector<T> and call erase with any type T that doesn't
write noexcept on its user-written special functions, right?

 - Usability: What about more general template functions that would
call named member functions, operators, etc. on the type T? Are we
going to have to correctly list every possible member function that
might be called? What about if it's an overloaded member function?

 - Generality/readiness: Has someone tried this system with complex
examples to see how it deals with issues like the above, such as
overloading? Note that many of these same problems have already been
analyzed in the context of concepts, which had a very similar model of
expressing things in terms of callee capabilities, but with less
syntactic overhead and more flexibility than the above, and that model
still hasn't been fully explored and understood in production-level
code.


>For vector::erase(), we have now the following specification.
> Throws: Nothing unless an exception is thrown by the copy constructor,
>   move constructor, assignment operator, or move assignment operator
>   of T.
>The above declaration looks very straightforward

To a template metaprogrammer, maybe. :)

Also, for this specific example, I think you would want to include
requiring a nothrow destructor too, right? How easy would it really be
to write these specifications correctly?

>based on this
>specification. It will give a compile error when erase() is called in a
>noexcept(true) function with T which doesn't fulfill the above
>conditions. That sounds fine and great.
>
>> and even when it does work more often than not quickly devolves into the
>> meaningless "throw(exception)".
>
>I don't think this will be a problem in C++ since such
>"throw(exception)" specification is the default (no exceptions
>specification). This is very different situation than that in Java.

I think the default doesn't matter; see above. It seems to me that
what matters is that checking is viral regardless of the default. That
is: if you require static checking, you are requiring all code that
can be called from a checked function must state its throws (Java) or
noexcept (your proposal for C++) clause fully and correctly, right?

And even a default of "throws something" is useless for the purpose of
static checking because it defeats any benefit of static exceptions.
In particular "by default may throw" would mean "by default can't be
called from statically exception checked code."


>Programmers won't be forced to write exception specifications

But everyone will be forced to write them a lot of the time if they
get used. To take your cases:

>until they
>write static exception specification for their own function,

.... which they cannot do until one is already written on every
function they need to call, because it's viral down. Unless they want
to work around it by writing unnecessary try/catches which would add
code clutter and can add some overhead.

>or they
>pass a type for a template which has a static exception specification.

.... or more generally want their function to be callable from any code
that has a static exception specification, because it's viral up.

It seems to me that, to get any benefit from static checking, you'd be
forced to write the specifications broadly throughout the code from
the bottom up. The only way I can see this is significantly better
than Java is that when you just give up on wanting to get the benefit,
instead of writing "throws Exception" everywhere as in Java you would
get to just stop writing the specifications because the default is
"throws something" -- but that isn't an argument in favor of static
checking because it means punting and not using the feature.


>> As often as I hear a C++ programmer
>> wish their exception specifications had Java's static semantics, I
>> hear a Java programmer wish theirs had non-static semantics.
>
>Static checking with noexcept is very different with Java's static
>checking, in that is default or not, that is a type list or a binary.
>I think the problem should be reconsidered separately, shouldn't it?

The default doesn't matter (except when you punt and stop trying to
use the feature, as above) because it must still be written explicitly
to offer any benefit.

The type list vs. binary changes the problem only in degree but not in
kind which is viral by nature.

It could be that I'm missing something, and please let me know if I
am. I don't think static checking has worked out well yet, and the
fundamental issues here would still be the same as Java encountered.

Herb


---
Herb Sutter   (herbsutter.wordpress.com)   (www.gotw.ca)

Convener, SC22/WG21 (C++)                  (www.gotw.ca/iso)
Architect, Visual C++                      (www.gotw.ca/microsoft)

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]



