Topic: std0X::expected_exception<T>()


Author: terekhov@web.de (Alexander Terekhov)
Date: Wed, 11 Jun 2003 19:24:50 +0000 (UTC)
Raw View
David Abrahams wrote:
[...]
> >      if (!std::expected_exception<T>()) {
> >        throw T(/*...*/);
> >      }
> >
> >  is equivalent to:
> >
> >      if (!std::expected_exception<T>()) {
> >        try {
> >          throw T(/*...*/);
> >        }
> >        catch(const T&) {
> >          std::unexpected();
> >        }
> >      }
> >  ...."
> >
> >
> > Would you vote against it? Why?
>
> I appreciate what you're trying to do, and I would certainly vote for
> std::expected_exception by itself if implementors tell me it's
> feasible.  There are two problems I see:
>
>    1. I'm pretty sure it's not feasible to implement for compilers
>       with dumb SJLJ-style EH (c.f. MSVC and quite a few GCCs - do all
>       GCC3.x use the new ABI? I think they don't).  If I'm right,
>       voting for it would force ABI breakage for those
>       implementations.  I'm not sure how acceptable that is for C++0X,
>       but I'm guessing it would send customers screaming.

Well, nobody's complaining thus far. ;-) ABI breakage aside for a
moment, it can be implemented even with SJLJ-style EH, I think.

>
>    2. You appear to be slipping in a subtle change in semantics for
>       throwing an exception for which there is no handler: you are
>       requiring that there is NO unwinding (except, possibly, the
>       variables in the throw's enclosing block (?)), and that

No unwinding at all.

>       unexpected is unconditionally called immediately.  I think
>       that's a separate issue and should be considered separately.
>       I'm not sure whether it's acceptable to change the semantics in
>       that way.

Why are you not sure whether it's acceptable? Note that the current
semantics that require std::unexpected() and terminate() handlers
"fly together with an unexpected exception" way up to the injected
catch(...) in the function-try-block (of a fucntion with an ES) is
nothing but a violation of RAII "principles" and is a rather serious
defect on its own, I'd say.

The only explanation that I have for the current silliness is that
Stroustrup&Co were designing it under the "assumption" that <quote>
On other systems, it is architecturally close to impossible not to
invoke the destructors while searching for a handler </quote> (Pg.
381, TC++PL SE).

Interestingly enough, he also writes <quote> When an exception is
caught, the exact point where it was thrown is generally not known.
This represents a loss of information compared to what a debugger
might know about the state of a program. In some C++ development
environments, for some programs, and for some people, it might
therefore be preferable not to catch exceptions from which the
program isn't designed to recover. </quote> And how does this fit
together with catch(...)-injected exception specifications? Note
that debugging aside, mandatory 2-phase EH would also facilitate
robust and reliable "failover"... and faster running programs: I
mean optimizations for throw()-nothing calls AND implicit "throw
nothing" regions that do contain some throwing calls but can be
compiled as throw()-nothing code due to the knowledge [based on
ESpecs of enclosing function(s)] that those exceptions are totally
unexpected and will never propagate even if something wrong happens
(something unexpected [e.g. std::logic_error ;-) ] gets thrown).

It's really time to mandate the mandatory 2-phase EH in Std. C++.

Well, the question is whether there's a realistic chance of that
happening -- is there any wiliness to do it on the part of the
committee members (details aside for a moment)? Please let me
know... we could then discuss some details (if the answer is yes),
I guess. ;-)

regards,
alexander.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dave@boost-consulting.com (David Abrahams)
Date: Fri, 13 Jun 2003 18:54:15 +0000 (UTC)
Raw View
terekhov@web.de (Alexander Terekhov) writes:

> David Abrahams wrote:
> [...]
>> >      if (!std::expected_exception<T>()) {
>> >        throw T(/*...*/);
>> >      }
>> >
>> >  is equivalent to:
>> >
>> >      if (!std::expected_exception<T>()) {
>> >        try {
>> >          throw T(/*...*/);
>> >        }
>> >        catch(const T&) {
>> >          std::unexpected();
>> >        }
>> >      }
>> >  ...."
>> >
>> >
>> > Would you vote against it? Why?
>>
>> I appreciate what you're trying to do, and I would certainly vote for
>> std::expected_exception by itself if implementors tell me it's
>> feasible.  There are two problems I see:
>>
>>    1. I'm pretty sure it's not feasible to implement for compilers
>>       with dumb SJLJ-style EH (c.f. MSVC and quite a few GCCs - do all
>>       GCC3.x use the new ABI? I think they don't).  If I'm right,
>>       voting for it would force ABI breakage for those
>>       implementations.  I'm not sure how acceptable that is for C++0X,
>>       but I'm guessing it would send customers screaming.
>
> Well, nobody's complaining thus far. ;-) ABI breakage aside for a
> moment, it can be implemented even with SJLJ-style EH, I think.

How?  On what do you base that assessment?

>>    2. You appear to be slipping in a subtle change in semantics for
>>       throwing an exception for which there is no handler: you are
>>       requiring that there is NO unwinding (except, possibly, the
>>       variables in the throw's enclosing block (?)), and that
>
> No unwinding at all.
>
>>       unexpected is unconditionally called immediately.  I think
>>       that's a separate issue and should be considered separately.
>>       I'm not sure whether it's acceptable to change the semantics in
>>       that way.
>
> Why are you not sure whether it's acceptable?

Some people may be counting on their implementation's current
behavior, and vendors may be unwilling to change that underneath their
customers.  It's not a question of whether it's acceptable to *me*,
really.

> Note that the current semantics that require std::unexpected() and
> terminate() handlers "fly together with an unexpected exception" way
> up to the injected catch(...) in the function-try-block (of a
> fucntion with an ES)

That's a very poetic description, but I can't tell what it means.
Would you mind using the accepted terminology?

> is nothing but a violation of RAII "principles"

Which principles are those?

> and is a rather serious defect on its own, I'd say.
>
> The only explanation that I have for the current silliness is that
> Stroustrup&Co were designing it under the "assumption" that <quote>
> On other systems, it is architecturally close to impossible not to
> invoke the destructors while searching for a handler </quote> (Pg.
> 381, TC++PL SE).

I believe that is the case with SJLJ-style EH.

> Interestingly enough, he also writes <quote> When an exception is
> caught, the exact point where it was thrown is generally not known.
> This represents a loss of information compared to what a debugger
> might know about the state of a program. In some C++ development
> environments, for some programs, and for some people, it might
> therefore be preferable not to catch exceptions from which the
> program isn't designed to recover. </quote> And how does this fit
> together with catch(...)-injected exception specifications?

What does that mean?

> Note that debugging aside, mandatory 2-phase EH would also
> facilitate robust and reliable "failover"...

Isn't 2-phase EH something yet again completely different from what
you've been discussing here so far?

> and faster running
> programs: I mean optimizations for throw()-nothing calls AND
> implicit "throw nothing" regions that do contain some throwing calls
> but can be compiled as throw()-nothing code due to the knowledge
> [based on ESpecs of enclosing function(s)] that those exceptions are
> totally unexpected and will never propagate even if something wrong
> happens (something unexpected [e.g. std::logic_error ;-) ] gets
> thrown).

Those optimizations are already possible.
>
> It's really time to mandate the mandatory 2-phase EH in Std. C++.
>
> Well, the question is whether there's a realistic chance of that
> happening -- is there any wiliness to do it on the part of the
> committee members (details aside for a moment)? Please let me
> know...

How should I know?  It's not something I've been polling people on.
My guess is most of them don't even understand the problem (if there
is one).  The way to fix that, as I've told you more times than I can
count, is to write a DR or a paper where all your ideas and arguments
are collected cogently in one static place.  Even if I get to the
point of understanding your POV in this NG thread, it's very likely
that I'll forget the details of the issue over the next week.

> we could then discuss some details (if the answer is yes), I
> guess. ;-)

I'm not going to waste my time talking about details until there's a
paper, I think.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: terekhov@web.de (Alexander Terekhov)
Date: Sat, 14 Jun 2003 19:43:48 +0000 (UTC)
Raw View
David Abrahams wrote: ....

In a couple of days from now I'll try to address some of your points (in
a reply to your "[repost]" message). For now, let me put it this way:

#include <stdio.h>

// volatile aside for a moment...

#define TRY {                         \
  int __handlers_registered = 0;      \
  do {                                \
    if (__handlers_registered) {      \

#define CATCH(__URL)                  \
    }                                 \
    if (!__handlers_registered) {     \
      printf("record %s\n", __URL);   \
    }                                 \
    else {                            \
      printf("unwind %s\n", __URL);   \
    }                                 \
    {                                 \

#define ENDTRY                        \
    }                                 \
  } while (!__handlers_registered++); \
};                                    \

int main() {
  printf("\nDear David, Herb, and/or \"whoever interested\",\n\n");
  TRY {
    printf("please follow ALL the embedded links and try to...\n");
  }
  CATCH("http://google.com/groups?threadm=3EE9F54A.EC545F67%40web.de") {
  }
  ENDTRY
  printf("once/iff you'll have some spare time, of course.\n\nTIA.\n");
}

regards,
alexander.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: terekhov@web.de (Alexander Terekhov)
Date: Fri, 6 Jun 2003 21:06:11 +0000 (UTC)
Raw View
"....
 template<class T> bool expected_exception() throw();
 Returns: true if matching handler is found.
 Notes: if expected_exception<T>() returns false then
 throwing T (at the point of expected_exception<T>()
 invocation) will result in the invocation of unexpected()
 handler with an exception consider caught. In effect,
 (in this new edition of this International Standard:-)

     if (!std::expected_exception<T>()) {
       throw T(/*...*/);
     }

 is equivalent to:

     if (!std::expected_exception<T>()) {
       try {
         throw T(/*...*/);
       }
       catch(const T&) {
         std::unexpected();
       }
     }
 ...."


Would you vote against it? Why?

TIA.

Well, "the context" is this:

http://lists.boost.org/MailArchives/boost/msg48162.php
http://lists.boost.org/MailArchives/boost/msg48211.php
([boost] Re: Exception handling... it's time to fix the
 http://www.boost.org/more/error_handling.html)

regards,
alexander.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dave@boost-consulting.com (David Abrahams)
Date: Mon, 9 Jun 2003 01:39:52 +0000 (UTC)
Raw View
terekhov@web.de (Alexander Terekhov) writes:

> "....
>  template<class T> bool expected_exception() throw();
>  Returns: true if matching handler is found.
>  Notes: if expected_exception<T>() returns false then
>  throwing T (at the point of expected_exception<T>()
>  invocation) will result in the invocation of unexpected()
>  handler with an exception consider caught. In effect,
>  (in this new edition of this International Standard:-)
>
>      if (!std::expected_exception<T>()) {
>        throw T(/*...*/);
>      }
>
>  is equivalent to:
>
>      if (!std::expected_exception<T>()) {
>        try {
>          throw T(/*...*/);
>        }
>        catch(const T&) {
>          std::unexpected();
>        }
>      }
>  ...."
>
>
> Would you vote against it? Why?

I appreciate what you're trying to do, and I would certainly vote for
std::expected_exception by itself if implementors tell me it's
feasible.  There are two problems I see:

   1. I'm pretty sure it's not feasible to implement for compilers
      with dumb SJLJ-style EH (c.f. MSVC and quite a few GCCs - do all
      GCC3.x use the new ABI? I think they don't).  If I'm right,
      voting for it would force ABI breakage for those
      implementations.  I'm not sure how acceptable that is for C++0X,
      but I'm guessing it would send customers screaming.

   2. You appear to be slipping in a subtle change in semantics for
      throwing an exception for which there is no handler: you are
      requiring that there is NO unwinding (except, possibly, the
      variables in the throw's enclosing block (?)), and that
      unexpected is unconditionally called immediately.  I think
      that's a separate issue and should be considered separately.
      I'm not sure whether it's acceptable to change the semantics in
      that way.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: pasa@lib.hu ("Balog Pal")
Date: Wed, 11 Jun 2003 18:04:09 +0000 (UTC)
Raw View
"Alexander Terekhov" <terekhov@web.de> wrote in message
news:3EE08DDC.A3A7A32D@web.de...

>  template<class T> bool expected_exception() throw();
>  Returns: true if matching handler is found.

Is that really useful?

Suppose I have a fragment:

try {  foo(); }
catch(...)
{
    Rollback();
    throw;
}

your stuff is called from some descendant of foo(). it will detect any
exception az expected. (do you intend that?  there IS a handler)

Then probably throw something that may end up unhandled.

Paul


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: terekhov@web.de (Alexander Terekhov)
Date: Wed, 11 Jun 2003 18:33:24 +0000 (UTC)
Raw View
Balog Pal wrote:
>
> "Alexander Terekhov" <terekhov@web.de> wrote in message
> news:3EE08DDC.A3A7A32D@web.de...
>
> >  template<class T> bool expected_exception() throw();
> >  Returns: true if matching handler is found.
>
> Is that really useful?
>
> Suppose I have a fragment:
>
> try {  foo(); }
> catch(...)
> {
>     Rollback();
>     throw;
> }

Rather: <http://google.com/groups?selm=3EC382B0.BE8CD854%40web.de>

  template<class _FwdIt, class _Tval> inline
  void _Uninit_fill(_FwdIt _First, _FwdIt _Last, const _Tval& _Val,
          _Nonscalar_ptr_iterator_tag)
  {       // copy _Val throughout raw [_First, _Last), arbitrary type
    _FwdIt _Next = _First;
    try {
      for (; _First != _Last; ++_First)
        _Construct(&*_First, _Val);
    }
    action_on_propagation_of(...) {  /* THIS DOESN'T CATCH *UNEXPECTED* EXCEPTIONS */
                                     /* THIS DOES RETHROW EXCEPTIONS AUTOMATICALLY */
                                     /* NOTHING ELSE CAN BE THROWN FROM THIS SCOPE */
      for (; _Next != _First; ++_Next)
        _Destroy(&*_Next);
    }
  }

Clarification 1: <http://google.com/groups?selm=3D8F4994.39A7596C%40web.de>

Okay, "a point" is this: Dinkum C++ Library [The Standard C++ Library
implementation] uses catch(...)/rethrow... and THIS {currently} doesn't
work on many threaded C++ implementations [on AIX, Solaris, etc.] w.r.t.
thread cancellation and thread exit (pthread_exit()) "exceptions". RAII
"workarounds" (even for cleanup-only) would really help here. Another
problem is that catch(...)/rethrow (w/o ES-like protection) DOES "steal"
exceptions and provoke UNNEEDED unwinding. That's also BAD. "Soft-catch"/
action_on_propagation_of(<whatever>) would probably solve this in a
somewhat better way than "traditional" RAII.

Clarification 2: <http://google.com/groups?selm=3EBBD992.763C6E7A%40web.de>

It is NOT 'finally' because it fires only when some matching exception
is raised within its try-block scope AND there's a matching handler
found *somewhere else* in the surrounding dynamic context.  AFAICS,
'finally' doesn't work that way. The "action" thing can even examine
the propagating exception(e.g. using try { throw; } catch... technique)
and perhaps even append some info to it (catching by reference). The
key point is that "THIS DOESN'T CATCH *UNEXPECTED* EXCEPTIONS". You can
think of it as a sort of WEAK (it should have been that way from the
beginning) function-try-block handler of some constructor or destructor
because such handlers also rethrow exceptions "automatically". WEAK
simply means that it can't be a propagation target because it's just
not "visible" in the search phase.

>
> your stuff is called from some descendant of foo(). it will detect any
> exception az expected. (do you intend that?  there IS a handler)

I can protect my code from stealing UNEXPECTED exceptions by caller's
catch(...), catch(const std::exception&), whatever "catch-everything"
things via imposing restrictive exception specifications ON MY CODE.

I mean: <http://google.com/groups?selm=c29b5e33.0202161451.2ef75f1f%40posting.google.com>

void oper(); // could throws anything

void checked_oper_call() throw( SOME_KNOWN_EXPECTED_EXCEPTIONS )
{ oper(); }

try {
  checked_oper_call();
}
catch( ... ) // I know what I am doing/getting here,
             // just do not want to write many
             // catch clauses ;-)
{
  //...
}

>
> Then probably throw something that may end up unhandled.

That's what you've coded. If you don't like it then don't code it.

regards,
alexander.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]