[system][filesystem v3] Question about error_code arguments

A POSIX sub-group is looking at C++ bindings for POSIX. They are talking about a filesystem library binding at least loosely based on Boost.System, Boost.Filesystem, and C++ TR2. In looking at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2838.html, "Library Support for Hybrid Error Handling (Rev 2)", they are concerned about specifying hybrid error handling like this: void f(error_code& ec=throws()); They would rather see it specified like this: void f(error_code* ec=0); One particular concern is that as currently worded, the N2838 proposal requires throws() return a null reference, which they see as relying on undefined behavior. I wasn't at the meeting where the LWG asked that a null reference be mandated; my reading of the standard is that it is unclear if returning a null reference is or isn't undefined behavior. Some of the core folks seem to think it is undefined, but compilers accept it. Although the reference form is usual for C++, the use of anything other than the default is limited, and usually in low-level code at that. Although I could personally live with either form, I'm leaning slightly toward the pointer form. Regardless, I'd like to hear Boosters views on the two interfaces above. Which do you prefer? Why? --Beman

Beman Dawes wrote:
A POSIX sub-group is looking at C++ bindings for POSIX.
They are talking about a filesystem library binding at least loosely based on Boost.System, Boost.Filesystem, and C++ TR2.
In looking at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2838.html, "Library Support for Hybrid Error Handling (Rev 2)", they are concerned about specifying hybrid error handling like this:
void f(error_code& ec=throws());
They would rather see it specified like this:
void f(error_code* ec=0);
...
Regardless, I'd like to hear Boosters views on the two interfaces above. Which do you prefer? Why?
I prefer the pointer form, because it's idiomatic. The reference form is an invention.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Tuesday 20 October 2009, Peter Dimov wrote:
Beman Dawes wrote:
A POSIX sub-group is looking at C++ bindings for POSIX.
They are talking about a filesystem library binding at least loosely based on Boost.System, Boost.Filesystem, and C++ TR2.
In looking at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2838.html, "Library Support for Hybrid Error Handling (Rev 2)", they are concerned about specifying hybrid error handling like this:
void f(error_code& ec=throws());
They would rather see it specified like this:
void f(error_code* ec=0);
...
Regardless, I'd like to hear Boosters views on the two interfaces above. Which do you prefer? Why?
I prefer the pointer form, because it's idiomatic. The reference form is an invention.
I agree. I've never heard of a null reference in C++ before reading the original post. I thought one of the selling points of references was they can't be null. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) iEYEARECAAYFAkrd3LMACgkQ5vihyNWuA4UnPwCg1fbhc/bdPgUuANv+S3uW4n10 H/IAn1sMfUgjMtA5UYlBnbb3iYjjbQ6Q =vtTB -----END PGP SIGNATURE-----

Beman Dawes wrote:
One particular concern is that as currently worded, the N2838 proposal requires throws() return a null reference, which they see as relying on undefined behavior. ...
Although I could personally live with either form, I'm leaning slightly toward the pointer form.
Regardless, I'd like to hear Boosters views on the two interfaces above. Which do you prefer? Why?
I don't know the details, but I also would prefer the pointer interface. "null reference" reminds me of somebody actually checking against a null reference: void f(int& r) { if (&r) // check whether r is a null reference ... ; g(&r); } I have no problem if "r" could be undefined, i.e. somebody called "f(*p);" with a "p" that is null or undefined. I also don't have a problem if "g" checks the pointer it is passed in against null. However, if "f" itself checks its argument against being a null reference, then I'm disappointed. As another poster said: "I thought one of the selling points of references was they can't be null." I could probably live with returning an "undefined reference", and if somebody prefers this "undefined reference" to actually be a null reference to simplify debugging, why not. But as soon as he explicitly checks the reference against actually being a null reference, I think he is doing something wrong. Regards, Thomas

Thomas Klimpel wrote:
Beman Dawes wrote:
One particular concern is that as currently worded, the N2838 proposal requires throws() return a null reference, which they see as relying on undefined behavior. ...
Although I could personally live with either form, I'm leaning slightly toward the pointer form.
Regardless, I'd like to hear Boosters views on the two interfaces above. Which do you prefer? Why?
I don't know the details, but I also would prefer the pointer interface. "null reference" reminds me of somebody actually checking against a null reference:
void f(int& r) { if (&r) // check whether r is a null reference ... ; g(&r); }
I have no problem if "r" could be undefined, i.e. somebody called "f(*p);" with a "p" that is null or undefined. I also don't have a problem if "g" checks the pointer it is passed in against null. However, if "f" itself checks its argument against being a null reference, then I'm disappointed. As another poster said: "I thought one of the selling points of references was they can't be null."
My exact thoughts. michael -- ---------------------------------- Michael Caisse Object Modeling Designs www.objectmodelingdesigns.com

2009/10/20 Beman Dawes <bdawes@acm.org>:
Regardless, I'd like to hear Boosters views on the two interfaces above. Which do you prefer? Why?
Since it's neither polymorphic nor ownership-transferring, I really dislike the pointer version. Now, I have no idea how error_code is specified, but I thought it would have been something like this, which wouldn't require null references: struct error_code { static const int throw_instead = ~0; error_code(int c = 0) : code_(c) {} int code() const { return code_; } error_code &operator=(int c) { if (code_ == throw_instead) throw system_exception(c); code_ = c; return *this; } private: int code_; }; error_code throws_object(error_code::throw_instead); error_code &throws() { return throws_object; } That said, I'd much prefer the pointer version to anything that requires that implementation code check whether the address of a reference is null, despite my distaste at having to pass &error all over the place. ~ Scott

Scott McMurray wrote:
2009/10/20 Beman Dawes <bdawes@acm.org>:
Regardless, I'd like to hear Boosters views on the two interfaces above. Which do you prefer? Why?
Since it's neither polymorphic nor ownership-transferring, I really dislike the pointer version.
Now, I have no idea how error_code is specified, but I thought it would have been something like this, which wouldn't require null references:
struct error_code { static const int throw_instead = ~0; error_code(int c = 0) : code_(c) {} int code() const { return code_; } error_code &operator=(int c) { if (code_ == throw_instead) throw system_exception(c); code_ = c; return *this; } private: int code_; };
error_code throws_object(error_code::throw_instead); error_code &throws() { return throws_object; }
That said, I'd much prefer the pointer version to anything that requires that implementation code check whether the address of a reference is null, despite my distaste at having to pass &error all over the place.
+1, null references are a really weird idea, IMHO. We should not introduce such precedent in the language support library, especially since there is an alternative solution that achieves the same result in a natural way.

Beman Dawes wrote:
They are talking about a filesystem library binding at least loosely based on Boost.System, Boost.Filesystem, and C++ TR2.
Good!
In looking at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2838.html, "Library Support for Hybrid Error Handling (Rev 2)", they are concerned about specifying hybrid error handling like this:
void f(error_code& ec=throws());
When avoiding exceptions, that leads to this code: error_code error; f(error);
They would rather see it specified like this:
void f(error_code* ec=0);
error_code error; f(&error); As Scott McMurray noted, the call doesn't transfer ownership and isn't polymorphic. However, using a null pointer to indicate the absence of something is idiomatic as Peter Dimov noted. From a purely esthetic point of view, I prefer not having to take the address of the error_code to call such a function.
One particular concern is that as currently worded, the N2838 proposal requires throws() return a null reference, which they see as relying on undefined behavior. I wasn't at the meeting where the LWG asked that a null reference be mandated; my reading of the standard is that it is unclear if returning a null reference is or isn't undefined behavior. Some of the core folks seem to think it is undefined, but compilers accept it.
As with others, this makes me very uncomfortable. I'd prefer that it be worded as an unspecified reference and that dereferencing it would result in undefined behavior. However, that begs the question: how does the function determine whether to throw an exception. If throws() returns an error_code instance that throws when the error is set, then there's no need for a null reference. Unfortunately, that has a performance downside: the function must be called and the temporary must be created or a reference to a global object must be created for all calls that use the default. A null pointer default must be cheaper. Given that this scheme will be standardized, it is quite reasonable to think that compiler vendors will apply suitable magic to eliminate the performance downside (auto-generate overloads, for example).
Although the reference form is usual for C++, the use of anything other than the default is limited, and usually in low-level code at that. Although I could personally live with either form, I'm leaning slightly toward the pointer form.
I have no experience with such functions, so I can't weigh in on the relative use of the default versus providing an error_code. Given the widening use cases for this approach, I doubt there is a general case one can cite. (Certainly those coding in environments without exceptions would bias the numbers.) In summary, I favor the reference interface so long as there is no mention of a null reference, provided compiler vendors think it can be done optimally. Otherwise, I can live with the pointer interface. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

Stewart, Robert wrote:
Beman Dawes wrote:
One particular concern is that as currently worded, the N2838 proposal requires throws() return a null reference, which they see as relying on undefined behavior. I wasn't at the meeting where the LWG asked that a null reference be mandated; my reading of the standard is that it is unclear if returning a null reference is or isn't undefined behavior. Some of the core folks seem to think it is undefined, but compilers accept it.
As with others, this makes me very uncomfortable. I'd prefer that it be worded as an unspecified reference and that dereferencing it would result in undefined behavior. However, that begs the question: how does the function determine whether to throw an exception. If throws() returns an error_code instance that throws when the error is set, then there's no need for a null reference. Unfortunately, that has a performance downside: the function must be called and the temporary must be created or a reference to a global object must be created for all calls that use the default. A null pointer default must be cheaper.
I think the performance cost of checking a reference or pointer for validity and checking some property in the error_code instance will be the same. After all, in both cases it comes down to a single comparison of two integers. Even if referencing the global default instance does add overhead, I bet it is negligible.

On Tue, Oct 20, 2009 at 12:56 PM, Andrey Semashev <andrey.semashev@gmail.com> wrote:
Stewart, Robert wrote:
Beman Dawes wrote:
One particular concern is that as currently worded, the N2838 proposal requires throws() return a null reference, which they see as relying on undefined behavior. I wasn't at the meeting where the LWG asked that a null reference be mandated; my reading of the standard is that it is unclear if returning a null reference is or isn't undefined behavior. Some of the core folks seem to think it is undefined, but compilers accept it.
As with others, this makes me very uncomfortable. I'd prefer that it be worded as an unspecified reference and that dereferencing it would result in undefined behavior. However, that begs the question: how does the function determine whether to throw an exception. If throws() returns an error_code instance that throws when the error is set, then there's no need for a null reference. Unfortunately, that has a performance downside: the function must be called and the temporary must be created or a reference to a global object must be created for all calls that use the default. A null pointer default must be cheaper.
I think the performance cost of checking a reference or pointer for validity and checking some property in the error_code instance will be the same. After all, in both cases it comes down to a single comparison of two integers. Even if referencing the global default instance does add overhead, I bet it is negligible.
I prefer a references interface from ease of use, however it should never have a null pointer. Why not have two functions of the same name, one takes a reference, the other a pointer, thus you can handle both cases and enforced that the reference cannot be null.

OvermindDL1 wrote:
Stewart, Robert wrote:
Beman Dawes wrote:
One particular concern is that as currently worded, the N2838 proposal requires throws() return a null reference, which they see [snip]
Why not have two functions of the same name, one takes a reference, the other a pointer, thus you can handle both cases and enforced that the reference cannot be null.
If you read the referenced proposal, you'll note that the idea was to avoid exploding interfaces to account for all functions using this error handling approach. That is, for every such function, there must be an additional overload, whereas a single overload suffices with the proposed design. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

Andrey Semashev wrote:
Stewart, Robert wrote:
Beman Dawes wrote:
set, then there's no need for a null reference. Unfortunately, that has a performance downside: the function must be called and the temporary must be created or a reference to a global object must be created for all calls that use the default. A null pointer default must be cheaper.
I think the performance cost of checking a reference or pointer for validity and checking some property in the error_code instance will be the same. After all, in both cases it comes down to a single comparison of two integers. Even if referencing the global default instance does add overhead, I bet it is negligible.
I wasn't referring to checking the reference or pointer. Rather, I was pointing out that the reference must be bound to something when the default is accepted. Every call using the default implies code that acquires an object or reference to one to which the formal parameter can be bound. That is costlier than simply passing a null pointer unless some compiler magic is involved. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

Stewart, Robert wrote:
Andrey Semashev wrote:
Stewart, Robert wrote:
Beman Dawes wrote:
set, then there's no need for a null reference. Unfortunately, that has a performance downside: the function must be called and the temporary must be created or a reference to a global object must be created for all calls that use the default. A null pointer default must be cheaper. I think the performance cost of checking a reference or pointer for validity and checking some property in the error_code instance will be the same. After all, in both cases it comes down to a single comparison of two integers. Even if referencing the global default instance does add overhead, I bet it is negligible.
I wasn't referring to checking the reference or pointer. Rather, I was pointing out that the reference must be bound to something when the default is accepted. Every call using the default implies code that acquires an object or reference to one to which the formal parameter can be bound. That is costlier than simply passing a null pointer unless some compiler magic is involved.
The call to throws() can be inlined so that the global object acquisition turns into loading its address in a register. The address is known at compile time, so there's little difference between loading a zero into a pointer/reference argument and loading a valid address into a reference argument. No magic needed for this to happen.

Andrey Semashev wrote:
Stewart, Robert wrote:
I wasn't referring to checking the reference or pointer. Rather, I was pointing out that the reference must be bound to something when the default is accepted. Every call using the default implies code that acquires an object or reference to one to which the formal parameter can be bound. That is costlier than simply passing a null pointer unless some compiler magic is involved.
The call to throws() can be inlined so that the global object acquisition turns into loading its address in a register. The address is known at compile time, so there's little difference between loading a zero into a pointer/reference argument and loading a valid address into a reference argument. No magic needed for this to happen.
If the global object is created before all code calling throws() is done, then its address can be taken safely by multiple threads. Doing so requires compiler/runtime magic. If the global object is created each time, there's code to create that object for each call accepting the default. I'm not speculating whether that construction is trivial, so there is, at least potentially, a cost per call accepting the default in such a case. Finally, the zero for a null pointer default can be coded close to the call or even embedded in an instruction. Fetching the address of a global object cannot so optimized, so every call accepting the default incurs a greater cost. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

Andrey Semashev wrote:
I think the performance cost of checking a reference or pointer for validity and checking some property in the error_code instance will be the same. After all, in both cases it comes down to a single comparison of two integers. Even if referencing the global default instance does add overhead, I bet it is negligible. No, it isn't. The null pointer will be in a register, while the global object might not even be in the cache. And this for functions that are called by the thousands per second on a busy server.
Detlef PS: This was one of the main reasons why the POSIX/C++ group is in favour of the pointer.

AMDG Detlef Vollmann wrote:
Andrey Semashev wrote:
I think the performance cost of checking a reference or pointer for validity and checking some property in the error_code instance will be the same. After all, in both cases it comes down to a single comparison of two integers. Even if referencing the global default instance does add overhead, I bet it is negligible. No, it isn't. The null pointer will be in a register, while the global object might not even be in the cache. And this for functions that are called by the thousands per second on a busy server.
Detlef
PS: This was one of the main reasons why the POSIX/C++ group is in favour of the pointer.
Why does the global object need to be read? static error_code throws_; error_code& throws() { return(throws_); } void f(error_code& ec = throws()) { if(&ec == &throws()) { throw ...; } else { .... } } This should not actually load anything except the address of the global error_code. The only advantage of using a null pointer is that it can be checked with a slightly simpler instruction. In Christ, Steven Watanabe

Steven Watanabe wrote:
Detlef Vollmann wrote:
Andrey Semashev wrote:
I think the performance cost of checking a reference or pointer for validity and checking some property in the error_code instance will be the same. After all, in both cases it comes down to a single comparison of two integers. Even if referencing the global default instance does add overhead, I bet it is negligible. No, it isn't. The null pointer will be in a register, while the global object might not even be in the cache.
Why does the global object need to be read?
static error_code throws_;
error_code& throws() { return(throws_); }
void f(error_code& ec = throws()) { if(&ec == &throws()) { throw ...; } else { .... } }
This should not actually load anything except the address of the global error_code. Loading the address from the symbol table also takes time. With a clever linker the cost might be very small, but if you look how many functions might get such signatures, and how often these functions are called, it's not negligible. It might be negligible on a CISC machine, but we don't only deal with CISC machines.
Detlef

Detlef Vollmann wrote:
Andrey Semashev wrote:
I think the performance cost of checking a reference or pointer for validity and checking some property in the error_code instance will be the same. After all, in both cases it comes down to a single comparison of two integers. Even if referencing the global default instance does add overhead, I bet it is negligible. No, it isn't. The null pointer will be in a register, while the global object might not even be in the cache. And this for functions that are called by the thousands per second on a busy server.
PS: This was one of the main reasons why the POSIX/C++ group is in favour of the pointer.
If the global object is used so often, it will likely be in cache. If not often, it doesn't matter. An whether the compiler can load a structure of size equal to int into a register is a question of the compiler's prosperity. Anyway, I'd prefer code clarity in this case instead of a possible tiny performance gain that will be swallowed by the surrounding code. Consider it in comparison with a file system operation cost, for example.

"Stewart, Robert" <Robert.Stewart@sig.com> wrote in message news:DF2E67F3D097004694C8428C70A3FD69046934E01F@msgbal516.ds.susq.com...
As Scott McMurray noted, the call doesn't transfer ownership and isn't polymorphic. However, using a null pointer to indicate the absence of something is idiomatic as Peter Dimov noted. From a purely esthetic point of view, I prefer not having to take the address of the error_code to call such a function.
How does having to pass an address screw up your esthetic view of the code? Maybe you could start redefining the language with some defines (grin). I usually try to avoid non-constant references in my own code, since they are obfuscating the code. I prefer the clarity of using the address operator to tell the person reading the code, what is happening.

Peter Foelsche wrote:
"Stewart, Robert" <Robert.Stewart@sig.com> wrote in message news:DF2E67F3D097004694C8428C70A3FD69046934E01F@msgbal516.ds.s usq.com...
As Scott McMurray noted, the call doesn't transfer ownership and isn't polymorphic. However, using a null pointer to indicate the absence of something is idiomatic as Peter Dimov noted. From a purely esthetic point of view, I prefer not having to take the address of the error_code to call such a function.
How does having to pass an address screw up your esthetic view of the code?
Have you looked at the definition of (a)esthetic? It is based upon one's notions of beauty, etc. I dislike putting the "&" wart in front of a variable when calling a function versus the "cleanliness" of not. It isn't as if I was saying doing so was wrong. I just like avoiding it when it isn't needful.
I usually try to avoid non-constant references in my own code, since they are obfuscating the code.
I recognize that deficiency of non-const references, but even when taking the address of something, it isn't clear whether the caller's object will be changed or the function merely allows for a value's absence (using a null pointer). Both approaches require knowledge of the function's signature, at least, to understand the effects on the arguments, so neither is superior in this regard.
I prefer the clarity of using the address operator to tell the person reading the code, what is happening.
All that does -- at the call site -- is indicate that the function takes a pointer. Whether the caller's object is modified, the argument is optional, or both is not indicated. There is no additional clarity over references. I prefer to use raw pointers to make an argument optional, smart pointers to transfer or otherwise control ownership, and references for all else. You have other ideas. It's aesthetics. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

2009/10/20 Beman Dawes <bdawes@acm.org>:
Regardless, I'd like to hear Boosters views on the two interfaces above. Which do you prefer? Why?
Could it be spelt like this instead? void f(optional<error_code&> ec = {}); So it'd act like a pointer inside the function, but for users it'd look like passing a normal reference?

I will reluctantly drag my brain out of holiday mode to put in my 2c here :) On Tue, 20 Oct 2009 11:15 -0400, "Beman Dawes" <bdawes@acm.org> wrote:
A POSIX sub-group is looking at C++ bindings for POSIX.
They are talking about a filesystem library binding at least loosely based on Boost.System, Boost.Filesystem, and C++ TR2.
In looking at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2838.html, "Library Support for Hybrid Error Handling (Rev 2)", they are concerned about specifying hybrid error handling like this:
void f(error_code& ec=throws());
They would rather see it specified like this:
void f(error_code* ec=0); [...]
Although the reference form is usual for C++, the use of anything other than the default is limited, and usually in low-level code at that.
As background to my point of view, I would say that this experience is not true for Asio users. The use of the non-defaulted call (or rather, its equivalent in Asio) is not limited, but widespread. Where applicable, Asio provides overloads: void f(); error_code f(error_code& ec); The throwing overloads are most typically in small programs or at program startup. Non-trivial programs will tend towards the second, non-throwing overload. It is the nature of network applications to react to errors as part of normal control flow, and exception handling is not a good approach for that.
Regardless, I'd like to hear Boosters views on the two interfaces above. Which do you prefer? Why?
First, allow me to register my strong dislike for the pointer form. In fact, I am not in favour of any specification that disallows the existence of two separate overloads: throwing and non-throwing. This: void f(error_code* ec = 0); supports both throwing and non-throwing modes. From the compiler's point of view, any calling code must also support exceptions and so a space and/or time cost is paid for unwinding, even if it is not required. A two-overload approach lets a library do something like: void f(); void f(error_code& ec) [[nothrow]]; In user code that calls the second form pays no cost for exception handling, and the compiler may do more static analysis and optimisation based on the nothrow attribute. It seems a bit odd to be quibbling over the cost of comparing pointers when some costs of exception handling are forced on everybody. Second, I do not pay the "explosion" of overloads argument. (Yes, there is a doubling.) The potential "explosion" comes from a throwing operation with defaulted arguments: void f(int a, int b = 0, int c = 0); where ideally the user would like to see the following non-throwing variants: void f(int a, error_code& ec); void f(int a, int b, error_code& ec); void f(int a, int b, int c, error_code& ec); However the proposed pointer form would be void f(int a, int b = 0, int c = 0, error_code* ec = 0); And so a user must specify all arguments to use the non-throwing form. If you're happy to require users to do so, then the only non-throwing reference-based overload required is: void f(int a, int b, int c, error_code& ec); I have had some Asio users complain that I have left out some non-throwing overloads. They now have to be aware of the default arguments where otherwise they could have ignored them. Therefore, the "explosion" is a cost that can be paid by a library to improve usability, but it is not inherent in the overload approach. However, it's true there is a doubling of overloads. In my opinion it is a cost worth paying (in specification and implementation) to allow users to avoid the costs of exception handling. In my experience, it's not *that* big a cost anyway. So as I said, I'm not in favour of a specification that excludes that approach. If there was to be a change to the throwing/non-throwing error_code idiom, then what I would suggest is putting the error_code parameter *first*. For example: void f(int a, int b = 0, int c = 0); void f(error_code& ec, int a, int b = 0, int c = 0); This avoids the explosion issue due to defaulted arguments, although you still get doubling. What's especially nice is that it should work with C++0x variadic templates, while the other approaches do not AFAIK. Cheers, Chris

Christopher Kohlhoff wrote:
I will reluctantly drag my brain out of holiday mode to put in my 2c here :)
Sorry to drag your brain in unwelcome directions, but thanks for taking the time to reply:-)
On Tue, 20 Oct 2009 11:15 -0400, "Beman Dawes" <bdawes@acm.org> wrote:
A POSIX sub-group is looking at C++ bindings for POSIX.
They are talking about a filesystem library binding at least loosely based on Boost.System, Boost.Filesystem, and C++ TR2.
In looking at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2838.html, "Library Support for Hybrid Error Handling (Rev 2)", they are concerned about specifying hybrid error handling like this:
void f(error_code& ec=throws());
They would rather see it specified like this:
void f(error_code* ec=0); [...]
Although the reference form is usual for C++, the use of anything other than the default is limited, and usually in low-level code at that.
As background to my point of view, I would say that this experience is not true for Asio users. The use of the non-defaulted call (or rather, its equivalent in Asio) is not limited, but widespread.
Point taken.
Where applicable, Asio provides overloads:
void f(); error_code f(error_code& ec);
The throwing overloads are most typically in small programs or at program startup. Non-trivial programs will tend towards the second, non-throwing overload. It is the nature of network applications to react to errors as part of normal control flow, and exception handling is not a good approach for that.
Regardless, I'd like to hear Boosters views on the two interfaces above. Which do you prefer? Why?
First, allow me to register my strong dislike for the pointer form. In fact, I am not in favour of any specification that disallows the existence of two separate overloads: throwing and non-throwing.
The point of the paper was to allow implementors to provide two separate overloads if they prefer. I'm doing so for some of the Boost.Filesystem operational functions. By the way, I agree with Thomas Witt's assertion that the second form return void so that the function can later be changed to return some useful value without disruption to existing code, and for consistency with functions that already return a non-void result.
This:
void f(error_code* ec = 0);
supports both throwing and non-throwing modes. From the compiler's point of view, any calling code must also support exceptions and so a space and/or time cost is paid for unwinding, even if it is not required.
A two-overload approach lets a library do something like:
void f(); void f(error_code& ec) [[nothrow]];
Right. That's what the paper was supposed to allow, or at least a version without the [[nothrow]]. I guess that didn't come through clearly enough. Aside 1: I apologize; I wasn't following [[nothrow]] through the committee, and hadn't even considered that it might impact error handling. Aside 2: Isn't the syntax "void f [[nothrow]] (error_code& ec);" rather than "void f(error_code& ec) [[nothrow]];"? Regardless, [[nothrow]] may mean that users expect and demand the two overload specification, even where it will have no measurable impact on performance. Even if [[nothrow]] doesn't make it into C++0x, I think the cat is out of the bag. User expectations and demands will just morph to: void f(); void f(error_code& ec); // [[nothrow]] Thus I'm going to seriously consider moving all of Boost.Filesystem to the two overload form, even though it nearly doubles the number of signatures.
In user code that calls the second form pays no cost for exception handling, and the compiler may do more static analysis and optimisation based on the nothrow attribute. It seems a bit odd to be quibbling over the cost of comparing pointers when some costs of exception handling are forced on everybody.
Second, I do not pay the "explosion" of overloads argument. (Yes, there is a doubling.) The potential "explosion" comes from a throwing operation with defaulted arguments:
void f(int a, int b = 0, int c = 0);
where ideally the user would like to see the following non-throwing variants:
void f(int a, error_code& ec); void f(int a, int b, error_code& ec); void f(int a, int b, int c, error_code& ec);
However the proposed pointer form would be
void f(int a, int b = 0, int c = 0, error_code* ec = 0);
And so a user must specify all arguments to use the non-throwing form. If you're happy to require users to do so, then the only non-throwing reference-based overload required is:
void f(int a, int b, int c, error_code& ec);
I have had some Asio users complain that I have left out some non-throwing overloads. They now have to be aware of the default arguments where otherwise they could have ignored them. Therefore, the "explosion" is a cost that can be paid by a library to improve usability, but it is not inherent in the overload approach.
However, it's true there is a doubling of overloads. In my opinion it is a cost worth paying (in specification and implementation) to allow users to avoid the costs of exception handling. In my experience, it's not *that* big a cost anyway. So as I said, I'm not in favour of a specification that excludes that approach.
If there was to be a change to the throwing/non-throwing error_code idiom, then what I would suggest is putting the error_code parameter *first*. For example:
void f(int a, int b = 0, int c = 0); void f(error_code& ec, int a, int b = 0, int c = 0);
This avoids the explosion issue due to defaulted arguments, although you still get doubling. What's especially nice is that it should work with C++0x variadic templates, while the other approaches do not AFAIK.
Interesting. I had briefly considered making error_code& ec the first argument, but rejected it as an unusual ordering of arguments that would draw criticism. But I hadn't considered the variadic template issue, which seems to be coming up in other designs, too. I'll give that some more thought. It really makes sense in the presence of other arguments with defaults, and for consistency perhaps even when a function has no defaulted arguments. Thanks for your comments! Although you just used [[nothrow]] in passing, it was a real eye-opener for me. --Beman

Interesting. I had briefly considered making error_code& ec the first argument, but rejected it as an unusual ordering of arguments that would draw criticism. But I hadn't considered the variadic template issue, which seems to be coming up in other designs, too.
What is unusual about having "output" parameters first? The return value itself always appears first, so it is only natural to begin the parameter list with the "other" output parameters.

Thomas Klimpel wrote:
What is unusual about having "output" parameters first? The return value itself always appears first, so it is only natural to begin the parameter list with the "other" output parameters.
That's my approach. It is consistent while allowing for defaulted arguments. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

Beman, From experience with using asio -- Can we (please?) have ignored() just like we have throws() that builds empty error_code? In quite a lot of places I don't want to deal with exceptions (since I don't know what thread it will come out to) and I don't care for the error too much (like retrieving address of possible disconnected endpoint). So, I have half of the code that looks like this socket.close(boost::system::error_code()); or, even more unreadable boost::asio::some_call(boost::system::error_code()).some_another_call(boost::system::error_code()); . Since then I introduced "ignored" macro (#define ignored boost::system::error_code()), code looks a bit more understandable, so I thought it might be a good idea to have it in a fact0ry-function form just like we will have throws()? Thank you very much, Andrey On Thu, 22 Oct 2009 07:27:22 -0600, Beman Dawes <bdawes@acm.org> wrote:
Christopher Kohlhoff wrote:
I will reluctantly drag my brain out of holiday mode to put in my 2c here :)
Sorry to drag your brain in unwelcome directions, but thanks for taking the time to reply:-)
On Tue, 20 Oct 2009 11:15 -0400, "Beman Dawes" <bdawes@acm.org> wrote:
A POSIX sub-group is looking at C++ bindings for POSIX.
They are talking about a filesystem library binding at least loosely based on Boost.System, Boost.Filesystem, and C++ TR2.
In looking at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2838.html, "Library Support for Hybrid Error Handling (Rev 2)", they are concerned about specifying hybrid error handling like this:
void f(error_code& ec=throws());
They would rather see it specified like this:
void f(error_code* ec=0); [...]
Although the reference form is usual for C++, the use of anything other than the default is limited, and usually in low-level code at that. As background to my point of view, I would say that this experience is not true for Asio users. The use of the non-defaulted call (or rather, its equivalent in Asio) is not limited, but widespread.
Point taken.
Where applicable, Asio provides overloads: void f(); error_code f(error_code& ec); The throwing overloads are most typically in small programs or at program startup. Non-trivial programs will tend towards the second, non-throwing overload. It is the nature of network applications to react to errors as part of normal control flow, and exception handling is not a good approach for that.
Regardless, I'd like to hear Boosters views on the two interfaces above. Which do you prefer? Why? First, allow me to register my strong dislike for the pointer form. In fact, I am not in favour of any specification that disallows the existence of two separate overloads: throwing and non-throwing.
The point of the paper was to allow implementors to provide two separate overloads if they prefer. I'm doing so for some of the Boost.Filesystem operational functions.
By the way, I agree with Thomas Witt's assertion that the second form return void so that the function can later be changed to return some useful value without disruption to existing code, and for consistency with functions that already return a non-void result.
This: void f(error_code* ec = 0); supports both throwing and non-throwing modes. From the compiler's point of view, any calling code must also support exceptions and so a space and/or time cost is paid for unwinding, even if it is not required. A two-overload approach lets a library do something like: void f(); void f(error_code& ec) [[nothrow]];
Right. That's what the paper was supposed to allow, or at least a version without the [[nothrow]]. I guess that didn't come through clearly enough.
Aside 1: I apologize; I wasn't following [[nothrow]] through the committee, and hadn't even considered that it might impact error handling.
Aside 2: Isn't the syntax "void f [[nothrow]] (error_code& ec);" rather than "void f(error_code& ec) [[nothrow]];"?
Regardless, [[nothrow]] may mean that users expect and demand the two overload specification, even where it will have no measurable impact on performance.
Even if [[nothrow]] doesn't make it into C++0x, I think the cat is out of the bag. User expectations and demands will just morph to:
void f(); void f(error_code& ec); // [[nothrow]]
Thus I'm going to seriously consider moving all of Boost.Filesystem to the two overload form, even though it nearly doubles the number of signatures.
In user code that calls the second form pays no cost for exception handling, and the compiler may do more static analysis and optimisation based on the nothrow attribute. It seems a bit odd to be quibbling over the cost of comparing pointers when some costs of exception handling are forced on everybody. Second, I do not pay the "explosion" of overloads argument. (Yes, there is a doubling.) The potential "explosion" comes from a throwing operation with defaulted arguments: void f(int a, int b = 0, int c = 0); where ideally the user would like to see the following non-throwing variants: void f(int a, error_code& ec); void f(int a, int b, error_code& ec); void f(int a, int b, int c, error_code& ec); However the proposed pointer form would be void f(int a, int b = 0, int c = 0, error_code* ec = 0); And so a user must specify all arguments to use the non-throwing form. If you're happy to require users to do so, then the only non-throwing reference-based overload required is: void f(int a, int b, int c, error_code& ec); I have had some Asio users complain that I have left out some non-throwing overloads. They now have to be aware of the default arguments where otherwise they could have ignored them. Therefore, the "explosion" is a cost that can be paid by a library to improve usability, but it is not inherent in the overload approach. However, it's true there is a doubling of overloads. In my opinion it is a cost worth paying (in specification and implementation) to allow users to avoid the costs of exception handling. In my experience, it's not *that* big a cost anyway. So as I said, I'm not in favour of a specification that excludes that approach. If there was to be a change to the throwing/non-throwing error_code idiom, then what I would suggest is putting the error_code parameter *first*. For example: void f(int a, int b = 0, int c = 0); void f(error_code& ec, int a, int b = 0, int c = 0); This avoids the explosion issue due to defaulted arguments, although you still get doubling. What's especially nice is that it should work with C++0x variadic templates, while the other approaches do not AFAIK.
Interesting. I had briefly considered making error_code& ec the first argument, but rejected it as an unusual ordering of arguments that would draw criticism. But I hadn't considered the variadic template issue, which seems to be coming up in other designs, too.
I'll give that some more thought. It really makes sense in the presence of other arguments with defaults, and for consistency perhaps even when a function has no defaulted arguments.
Thanks for your comments! Although you just used [[nothrow]] in passing, it was a real eye-opener for me.
--Beman

"Andrey Tcherepanov" <moyt63c02@sneakemail.com> wrote in message news:op.u17hoeykefd2ob@andrey-laptop.sod.shaw.ca...
socket.close(boost::system::error_code());
after 1996 (after C++ Exception Handling was introduced) I did not call close() anymore directly in my code -- it usually resides in a destructor. I also wonder what error code could close possibly return? LINUX man page tells me that there is * EBADF which cannot happen if the constructor was successful. * EINTR which should be dealt with in the destructor by calling close repeatedly

"Christopher Kohlhoff" <chris@kohlhoff.com> wrote in message news:1256082527.2327.1341115615@webmail.messagingengine.com...
supports both throwing and non-throwing modes. From the compiler's point of view, any calling code must also support exceptions and so a space and/or time cost is paid for unwinding, even if it is not required.
Socket functions may always run into errors. These errors cannot be ignored, since all the following code is based on, that the socket operation was successful. Can you give me a socket example, which can not result in an error? Creating a listening socket may fail, because of the port is already in use (this assumes that there is no need to seperately export socket/bind/listen). Creating a socket which connects to some well known address may also fail. Reading and writing from/to a socket may fail with an error, because the socket was closed on the other end.
I have had some Asio users complain that I have left out some non-throwing overloads.
I guess this are the same programmers, which use fixed-sized buffers.

"Christopher Kohlhoff" <chris@kohlhoff.com> wrote in message news:1256082527.2327.1341115615@webmail.messagingengine.com...
The throwing overloads are most typically in small programs or at program startup. Non-trivial programs will tend towards the second, non-throwing overload. It is the nature of network applications to react to errors as part of normal control flow, and exception handling is not a good approach for that.
You are the author of the asio library in boost? With this kind of thinking, how did you get this position?

Peter Foelsche wrote:
"Christopher Kohlhoff" <chris@kohlhoff.com> wrote in message news:1256082527.2327.1341115615@webmail.messagingengine.com...
The throwing overloads are most typically in small programs or at program startup. Non-trivial programs will tend towards the second, non-throwing overload. It is the nature of network applications to react to errors as part of normal control flow, and exception handling is not a good approach for that.
You are the author of the asio library in boost? With this kind of thinking, how did you get this position?
Such an attitude will not get you very far in this community. Any point you might try to make will get lost in the immaturity. Such banter just shows your inexperience with reactionary systems. I suspect you have a point you would like to make about the interface. If you keep the personal attacks out of the statement you will be more clearly heard. Regards - michael -- ---------------------------------- Michael Caisse Object Modeling Designs www.objectmodelingdesigns.com

On Oct 26, 2009, at 7:26 PM, Michael Caisse wrote:
Peter Foelsche wrote:
"Christopher Kohlhoff" <chris@kohlhoff.com> wrote in message news:1256082527.2327.1341115615@webmail.messagingengine.com ...
The throwing overloads are most typically in small programs or at program startup. Non-trivial programs will tend towards the second, non-throwing overload. It is the nature of network applications to react to errors as part of normal control flow, and exception handling is not a good approach for that.
You are the author of the asio library in boost? With this kind of thinking, how did you get this position?
Such an attitude will not get you very far in this community. Any point you might try to make will get lost in the immaturity. Such banter just shows your inexperience with reactionary systems.
Agreed. I am a huge proponent of using exception handling instead of error codes (virtually everywhere), but considering that ASIO is one of the best, and most cleverly, designed C++ libraries ever made (up there with Boost.Graph and Boost.MPL), one should be a tad careful before bantering like that. The likelihood of one's being a better C++- using designer than Christopher is not that high, statistically speaking...
I suspect you have a point you would like to make about the interface. If you keep the personal attacks out of the statement you will be more clearly heard.
If I were Christopher, I would kindly ask for instances in the ASIO library where exception handling would help readability, performance or any other aspect. I think there might be such cases, but that would be like whining about a pimple on Halle Berry's face. /David

"David Bergman" <David.Bergman@bergmangupta.com> wrote in message news:080E88A6-D02B-4AAD-B2FC-B9E6A8E97F5C@bergmangupta.com...
Agreed. I am a huge proponent of using exception handling instead of error codes (virtually everywhere), but considering that ASIO is one of the best, and most cleverly, designed C++ libraries ever made (up there with Boost.Graph and Boost.MPL), one should be a tad careful before bantering like that. The likelihood of one's being a better C++- using designer than Christopher is not that high, statistically speaking...
I've a lot of respect for some parts of the boost library -- e.g. mpl. I learned a lot from using the mpl. I also learned a lot from boost::variant and boost::any. Did you actually read my posts? He designed a socket library, which is full of protocols (Protocol is my word for a class-design, which requires that methods of an object be called in a particular order.). He also does not understand the usefulness of exception handling in larger software projects.
I suspect you have a point you would like to make about the interface. If you keep the personal attacks out of the statement you will be more clearly heard.
If I were Christopher, I would kindly ask for instances in the ASIO library where exception handling would help readability, performance or any other aspect. I think there might be such cases, but that would be like whining about a pimple on Halle Berry's face.
I think in 1996 I designed some classes to wrap UNIXs socket and io calls. There was a socket class calling socket() in the constructor and close() in the destructor without any other methods. This class does not need to be public, as it is useless for the enduser. Then there are classes, * which connect to a well known address (for usage as a client) * and a class calling bind() and listen() to a wellknown local address (for usage as a server) -- both classes are based on the socket class. These classes have cast functions to cast into a int -- the filedescriptor. Then there are implementation of some read-from-somewhere interface and some write-to-somewhere interface -- reading from a filedescriptor and writing to a filedescriptor. Such implementations of read-from-somewhere and write-to-somewhere can be combined to produce cached reading and writing. Then there was another layer using the XDR libraries to deal with machine independence, which was pretty complicated due to the crazy XDR interface (which UNIX API is not crazy?). And I think I had to deal with various UNIX hacks, like e.g. connect() returning immediately. The write-system call also had to be wrapped by setting/resetting the signal handler for SIGIO. All of these functions threw on error -- a system error object. This made debugging server-client systems much more easier than before, since now people knew the system error and the method which failed and maybe even the call-stack of the failed operation: Cannot start postprocessor in client mode! Because of Cannot connect to "hostname":portnumber! Because of No such host! ("Hostname"). I was only dealing with TCP/IP and not UDP.

On Oct 26, 2009, at 8:16 PM, Peter Foelsche wrote:
"David Bergman" <David.Bergman@bergmangupta.com> wrote in message news:080E88A6-D02B-4AAD-B2FC-B9E6A8E97F5C@bergmangupta.com ...
Agreed. I am a huge proponent of using exception handling instead of error codes (virtually everywhere), but considering that ASIO is one of the best, and most cleverly, designed C++ libraries ever made (up there with Boost.Graph and Boost.MPL), one should be a tad careful before bantering like that. The likelihood of one's being a better C++- using designer than Christopher is not that high, statistically speaking...
I've a lot of respect for some parts of the boost library -- e.g. mpl. I learned a lot from using the mpl. I also learned a lot from boost::variant and boost::any.
Did you actually read my posts?
Nope, just that particular uncalled for, and quite personal, bantering line.
He designed a socket library, which is full of protocols (Protocol is my word for a class-design, which requires that methods of an object be called in a particular order.). He also does not understand the usefulness of exception handling in larger software projects.
I suspect you have a point you would like to make about the interface. If you keep the personal attacks out of the statement you will be more clearly heard.
If I were Christopher, I would kindly ask for instances in the ASIO library where exception handling would help readability, performance or any other aspect. I think there might be such cases, but that would be like whining about a pimple on Halle Berry's face.
I think in 1996 I designed some classes to wrap UNIXs socket and io calls. There was a socket class calling socket() in the constructor and close() in the destructor without any other methods. This class does not need to be public, as it is useless for the enduser. Then there are classes, * which connect to a well known address (for usage as a client) * and a class calling bind() and listen() to a wellknown local address (for usage as a server) -- both classes are based on the socket class.
These classes have cast functions to cast into a int -- the filedescriptor.
Then there are implementation of some read-from-somewhere interface and some write-to-somewhere interface -- reading from a filedescriptor and writing to a filedescriptor. Such implementations of read-from-somewhere and write-to-somewhere can be combined to produce cached reading and writing.
Then there was another layer using the XDR libraries to deal with machine independence, which was pretty complicated due to the crazy XDR interface (which UNIX API is not crazy?).
And I think I had to deal with various UNIX hacks, like e.g. connect () returning immediately.
The write-system call also had to be wrapped by setting/resetting the signal handler for SIGIO.
I have written many such wrappers, and one very similar to this description - even using XDR - in 1992.
All of these functions threw on error -- a system error object. This made debugging server-client systems much more easier than before, since now people knew the system error and the method which failed and maybe even the call-stack of the failed operation:
Cannot start postprocessor in client mode! Because of Cannot connect to "hostname":portnumber! Because of No such host! ("Hostname").
I was only dealing with TCP/IP and not UDP.
Your argument is valid in most circumstances, but there are a few where error codes is more proper, as has been pointed out a few times on this list, such as when embedded environments without exception handling is targeted. OR: in asynchronous cases involving callbacks, which is often the case with Boost.Asio. Let us instead see how we can help Christopher improve (the already magnificent) Boost.Asio, by showing how exception handling would make code more readable/performant/whatever in that particular library. /David

"Michael Caisse" <boost@objectmodelingdesigns.com> wrote in message news:4AE6300A.8020806@objectmodelingdesigns.com...
You are the author of the asio library in boost? With this kind of thinking, how did you get this position? Such an attitude will not get you very far in this community. Any point you might try to make will get lost in the immaturity. Such banter just shows your inexperience with reactionary systems.
I suspect you have a point you would like to make about the interface. If you keep the personal attacks out of the statement you will be more clearly heard.
His statement showing missing experience, that I think my post was fully fitting the circumstances. I think exploitation of C++ Exception Handling after 1996 with Windows and OS/2 Compilers and much later on UNIXs is such a step forward, that I cannot in good concience leave such a statement unanswered.

"Peter Foelsche" <peter_foelsche@agilent.com> wrote in message news:hc5bkl$vni$1@ger.gmane.org...
I suspect you have a point you would like to make about the interface. If you keep the personal attacks out of the statement you will be more clearly heard.
His statement showing missing experience, that I think my post was fully fitting the circumstances. I think exploitation of C++ Exception Handling after 1996 with Windows and OS/2 Compilers and much later on UNIXs is such a step forward, that I cannot in good concience leave such a statement unanswered.
and I was also refering to the style asio library -- exporting unnecessary functionality (like separate calls to socket() and bind() and listen()) creating the possibility of wrong order of calls. Originally I made another post in this newsgroup with subject "asio library".

Peter Foelsche wrote:
"Michael Caisse" <boost@objectmodelingdesigns.com> wrote in message news:4AE6300A.8020806@objectmodelingdesigns.com...
You are the author of the asio library in boost? With this kind of thinking, how did you get this position? Such an attitude will not get you very far in this community. Any point you might try to make will get lost in the immaturity. Such banter just shows your inexperience with reactionary systems.
I suspect you have a point you would like to make about the interface. If you keep the personal attacks out of the statement you will be more clearly heard.
His statement showing missing experience, that I think my post was fully fitting the circumstances.
You assume he has little experience because he has different ideas than you? That's rather narrow minded. Isn't it possible that his experience is more extensive than your own and has led to different conclusions?
I think exploitation of C++ Exception Handling after 1996 with Windows and OS/2 Compilers and much later on UNIXs is such a step forward, that I cannot in good concience leave such a statement unanswered.
The problem is not that you have a contrary opinion. It is that you state it by belittling Christopher and anyone else who disagrees with you. Had you written something akin to, the following, you'd have started a dialogue rather than irked the community: "You're the author of Boost.Asio, right? I'm surprised. In my experience, exceptions are the most appropriate means to report errors in such a library because...." _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

Peter Foelsche wrote:
"Christopher Kohlhoff" <chris@kohlhoff.com> wrote in message news:1256082527.2327.1341115615@webmail.messagingengine.com...
The throwing overloads are most typically in small programs or at program startup. Non-trivial programs will tend towards the second, non-throwing overload. It is the nature of network applications to react to errors as part of normal control flow, and exception handling is not a good approach for that.
You are the author of the asio library in boost? With this kind of thinking, how did you get this position?
He got in this position by crafting, documenting, and submitting a highly useful and desirable library that the reviewing Boost community liked and accepted. Did you raise your concerns during the review? If so, they couldn't have been among the majority of opinions or the library wouldn't have been accepted. If not, constructive criticism might lead to Asio improvements even now. If you find the library so poorly designed and ill-conceived as to require starting from scratch, please submit your alternative. If it is accepted and found to be superior to Asio, users will abandon Asio for your library and all will win (I'm sure Christopher would be happy to have his users write their programs with a better library if one was available). Note that the options I've presented do not involve impugning Christopher's design skills or belittling the opinions of those that disagree with your viewpoint. You will not make progress in this community if you persist in attacking. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

"Beman Dawes" <bdawes@acm.org> wrote in message news:a61d44020910200815kedf3976t6e96a67e2f453271@mail.gmail.com...
A POSIX sub-group is looking at C++ bindings for POSIX.
They are talking about a filesystem library binding at least loosely based on Boost.System, Boost.Filesystem, and C++ TR2.
In looking at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2838.html, "Library Support for Hybrid Error Handling (Rev 2)", they are concerned about specifying hybrid error handling like this:
What is the sense of a C++ interface, which does not throw on error? I think meanwhile (this is 2009) we should be over the "I hate C++ Exception Handling" thinking.

On Oct 26, 2009, at 3:32 PM, Peter Foelsche wrote:
"Beman Dawes" <bdawes@acm.org> wrote in message news:a61d44020910200815kedf3976t6e96a67e2f453271@mail.gmail.com ...
A POSIX sub-group is looking at C++ bindings for POSIX.
They are talking about a filesystem library binding at least loosely based on Boost.System, Boost.Filesystem, and C++ TR2.
In looking at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2838.html , "Library Support for Hybrid Error Handling (Rev 2)", they are concerned about specifying hybrid error handling like this:
What is the sense of a C++ interface, which does not throw on error? I think meanwhile (this is 2009) we should be over the "I hate C++ Exception Handling" thinking.
Well said. Thank you. -- Marshall

Peter Foelsche wrote:
"Beman Dawes" <bdawes@acm.org> wrote in message news:a61d44020910200815kedf3976t6e96a67e2f453271@mail.gmail.com...
A POSIX sub-group is looking at C++ bindings for POSIX.
They are talking about a filesystem library binding at least loosely based on Boost.System, Boost.Filesystem, and C++ TR2.
In looking at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2838.html, "Library Support for Hybrid Error Handling (Rev 2)", they are concerned about specifying hybrid error handling like this:
What is the sense of a C++ interface, which does not throw on error? I think meanwhile (this is 2009) we should be over the "I hate C++ Exception Handling" thinking.
Some systems do not have exception handling (some embedded for example) and interfaces for libraries that want to be used in such environments need to not mandate it. Granted, an embedded system of that sort likely wont use a filesystem lib either ... but the point is valid for libraries as a whole. Additionally, see Christopher Kohlhoff's response to this thread which enumerates some excellent reasons. I think his email is "spot on". Best regards - michael -- ---------------------------------- Michael Caisse Object Modeling Designs www.objectmodelingdesigns.com

Peter Foelsche wrote:
"Beman Dawes" <bdawes@acm.org> wrote in message news:a61d44020910200815kedf3976t6e96a67e2f453271@mail.gmail.com...
A POSIX sub-group is looking at C++ bindings for POSIX.
They are talking about a filesystem library binding at least loosely based on Boost.System, Boost.Filesystem, and C++ TR2.
In looking at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2838.html, "Library Support for Hybrid Error Handling (Rev 2)", they are concerned about specifying hybrid error handling like this:
What is the sense of a C++ interface, which does not throw on error?
Others noted embedded environments -- very important today -- but let's look at a broader case. Throwing an exception is extremely expensive for many reasons. Some applications encounter errors regularly and often due to the nature of their environment or context. Such applications, if errors were reported using exceptions, would have high or widely varying latencies and generally sluggish performance. If errors are relatively infrequent, then the cleanliness of writing code without error checking at every turn, and the zero or near zero overhead of exception handling code when no exceptions are raised, means using exceptions is nearly ideal. Eventually, however, there's a threshhold at which the frequency of exceptions, given the cost to throw them when they do occur, overwhelms the processing time. In that case, exceptions are a problem, not the solution.
I think meanwhile (this is 2009) we should be over the "I hate C++ Exception Handling" thinking.
Perhaps there's room for other opinions on the use of exceptions now that we've moved beyond that phase and the "Exceptions are always the error handling scheme of choice in C++" phase? This error_code scheme allows one to choose whether to get an exception or not. Thus, one chooses when the overhead of throwing exceptions is acceptable and when not. Surely that's not controversial. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

"Stewart, Robert" <Robert.Stewart@sig.com> wrote in message news:DF2E67F3D097004694C8428C70A3FD69046F260E64@msgbal516.ds.susq.com...
Others noted embedded environments -- very important today -- but let's look at a broader case.
I was talking about C++. C++ includes exception handling. C++ without exception handling does not make any sense, as one cannot perform a fallible resource allocation inside a constructor.

Peter Foelsche wrote:
"Stewart, Robert" <Robert.Stewart@sig.com> wrote in message
Others noted embedded environments -- very important today
I was talking about C++. C++ includes exception handling. C++ without exception handling does not make any sense, as one cannot perform a fallible resource allocation inside a constructor.
I'm sure all of those using embedded C++ will be glad to know they were deluded all this time. C++ is a broad language. You get to choose which features you use. If you don't use the standard containers, for example, you won't get any exceptions from them. If you use only the non-throwing form of new, you won't get exceptions from failed memory allocations. If you write all of your code, including your constructors, such that they never throw exceptions, you won't get exceptions. Guess what? That's still C++, however restricted it may be. "Don't pay for what you don't use" is the guiding principle for the language. Boost is about libraries useful to a broad array of people using C++, not just those willing to use the entire array of features. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

"Stewart, Robert" <Robert.Stewart@sig.com> wrote in message news:DF2E67F3D097004694C8428C70A3FD69046F260F78@msgbal516.ds.susq.com...
I'm sure all of those using embedded C++ will be glad to know they were deluded all this time.
C++ is a broad language. You get to choose which features you use. If you don't use the standard containers, for example, you won't get any exceptions from them. If you use only the non-throwing form of new, you won't get exceptions from failed memory allocations. If you write all of your code, including your constructors, such that they never throw exceptions, you won't get exceptions. Guess what? That's still C++, however restricted it may be.
The amount of code required to deal with the possibility, that one of the preceding base or member objects did not successfully construct, prevents any serious usage of C++.

Peter Foelsche wrote:
The amount of code required to deal with the possibility, that one of the preceding base or member objects did not successfully construct, prevents any serious usage of C++.
Your assertion is false. A great deal of serious C++ was written before the language even had exceptions. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

On Oct 27, 2009, at 12:50 PM, Peter Foelsche wrote:
"Stewart, Robert" <Robert.Stewart@sig.com> wrote in message news:DF2E67F3D097004694C8428C70A3FD69046F260E64@msgbal516.ds.susq.com ...
Others noted embedded environments -- very important today -- but let's look at a broader case.
I was talking about C++. C++ includes exception handling. C++ without exception handling does not make any sense, as one cannot perform a fallible resource allocation inside a constructor.
There is no official recommendation for the language in-between EC++ and C++ - C++ minus exception handling - AFAIK, but it is no secret that Boost is targeting that "language" as well, and also C++/CLI to some extent. Strange as it might seem, quite sensical programs have been created in this unnamed language, even though one cannot use the sometimes nifty feature of throwing in a constructor. So, I fail to see how it "does not make any sense." /David

David Bergman wrote:
On Oct 27, 2009, at 12:50 PM, Peter Foelsche wrote:
Others noted embedded environments -- very important today -- but let's look at a broader case.
I was talking about C++. C++ includes exception handling. C++ without exception handling does not make any sense, as one cannot perform a fallible resource allocation inside a constructor.
There is no official recommendation for the language in-between EC++ and C++ - C++ minus exception handling - AFAIK, but it is no secret that Boost is targeting that "language" as well, and also C++/CLI to some extent.
Strange as it might seem, quite sensical programs have been created in this unnamed language, even though one cannot use the sometimes nifty feature of throwing in a constructor. So, I fail to see how it "does not make any sense."
I don't want to comment the ASIO-related argument, neither I want to convert anyone to anything. What I want to point out is that IMO, exceptions are sometimes undeservedly ignored for different reasons. One of such reasons is developer's commons, if he got used to code without exceptions and/or cannot use them properly for the lack of knowledge. Another reason is attempt to achieve overzealous portability, be that ancient buggy compilers from the dawn of C++ or some exotic platforms without exceptions support. All these reasons are valid, at least for now. But for how long? Developers eventually learn things or move to other languages (C?). Ancient compilers die, new ones become more popular and more efficient. Exotic platforms also either tend to decease or evolve. In my mind, error handling through exceptions should become more preferred over time. Expressing and honoring this tendency in the Standard for the coming 5 years may not be such a bad idea after all.

On Oct 27, 2009, at 1:43 PM, Andrey Semashev wrote: > David Bergman wrote: >> On Oct 27, 2009, at 12:50 PM, Peter Foelsche wrote: >>>> Others noted embedded environments -- very important today -- but >>>> let's look at a broader case. >>> >>> I was talking about C++. >>> C++ includes exception handling. >>> C++ without exception handling does not make any sense, >>> as one cannot perform a fallible resource allocation inside a >>> constructor. >> There is no official recommendation for the language in-between EC+ >> + and C++ - C++ minus exception handling - AFAIK, but it is no >> secret that Boost is targeting that "language" as well, and also C+ >> +/CLI to some extent. >> Strange as it might seem, quite sensical programs have been created >> in this unnamed language, even though one cannot use the sometimes >> nifty feature of throwing in a constructor. So, I fail to see how >> it "does not make any sense." > > I don't want to comment the ASIO-related argument, neither I want to > convert anyone to anything. > > What I want to point out is that IMO, exceptions are sometimes > undeservedly ignored for different reasons. One of such reasons is > developer's commons, if he got used to code without exceptions and/ > or cannot use them properly for the lack of knowledge. Another > reason is attempt to achieve overzealous portability, be that > ancient buggy compilers from the dawn of C++ or some exotic > platforms without exceptions support. All these reasons are valid, > at least for now. > > But for how long? Developers eventually learn things or move to > other languages (C?). Ancient compilers die, new ones become more > popular and more efficient. Exotic platforms also either tend to > decease or evolve. In my mind, error handling through exceptions > should become more preferred over time. Expressing and honoring this > tendency in the Standard for the coming 5 years may not be such a > bad idea after all. I agree with all you said, but (i) one should understand the *current* need for exception-less solutions and (ii) the idea that (C++) code without exception constructs is in some sense nonsensical is, well, nonsensical ;-) - all this while striving for exception handling everywhere possible and try to push compiler writers to make such handling even more efficient. /David

David Bergman wrote:
What I want to point out is that IMO, exceptions are sometimes undeservedly ignored for different reasons. One of such reasons is developer's commons, if he got used to code without exceptions and/or cannot use them properly for the lack of knowledge. Another reason is attempt to achieve overzealous portability, be that ancient buggy compilers from the dawn of C++ or some exotic platforms without exceptions support. All these reasons are valid, at least for now.
But for how long? Developers eventually learn things or move to other languages (C?). Ancient compilers die, new ones become more popular and more efficient. Exotic platforms also either tend to decease or evolve. In my mind, error handling through exceptions should become more preferred over time. Expressing and honoring this tendency in the Standard for the coming 5 years may not be such a bad idea after all.
I agree with all you said, but (i) one should understand the *current* need for exception-less solutions and (ii) the idea that (C++) code without exception constructs is in some sense nonsensical is, well, nonsensical ;-) - all this while striving for exception handling everywhere possible and try to push compiler writers to make such handling even more efficient.
Perhaps, we could mark the non-throwing overloads as deprecated in the Standard? Like strstreams, they are there but generally throwing overloads are more preferred.

Andrey Semashev wrote:
Perhaps, we could mark the non-throwing overloads as deprecated in the Standard? Like strstreams, they are there but generally throwing overloads are more preferred.
Why is it necessary to impose a single view on the language? Authors often give advice and situations demand certain concessions. Isn't it reasonable to accommodate many use cases? If you're too restrictive, you make C++ less appealing and users will choose other languages. Is that helpful? In the context of using error_code, I think it is quite reasonable to overload all functions such that those with an error_code parameter don't throw, but rather put their error information in that parameter for the caller to inspect, while the overloads without an error_code parameter throw exceptions. Those that prefer exceptions will not pass an error_code argument. Those that cannot or won't use exceptions can pass an error_code argument. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

Stewart, Robert wrote:
Andrey Semashev wrote:
Perhaps, we could mark the non-throwing overloads as deprecated in the Standard? Like strstreams, they are there but generally throwing overloads are more preferred.
Why is it necessary to impose a single view on the language? Authors often give advice and situations demand certain concessions. Isn't it reasonable to accommodate many use cases? If you're too restrictive, you make C++ less appealing and users will choose other languages. Is that helpful?
I wouldn't say that it would narrow the language in some way. You still get the same functionality, only error reporting mechanism is in question. Using exceptions for this purpose is, well... following the language spirit, so to say, while mandating a dual approach honors code diversity. I happened to support some code that used both exceptions and error codes for error reporting, and I must say it was a pain. I think, at least for educational purposes one form of functions (the throwing one) should be highlighted as preferred.

On Tue, Oct 27, 2009 at 7:47 PM, Andrey Semashev <andrey.semashev@gmail.com> wrote:
Why is it necessary to impose a single view on the language? Authors often give advice and situations demand certain concessions. Isn't it reasonable to accommodate many use cases? If you're too restrictive, you make C++ less appealing and users will choose other languages. Is that helpful?
I wouldn't say that it would narrow the language in some way. You still get the same functionality, only error reporting mechanism is in question. Using exceptions for this purpose is, well... following the language spirit, so to say, while mandating a dual approach honors code diversity. I happened to support some code that used both exceptions and error codes for error reporting, and I must say it was a pain. I think, at least for educational purposes one form of functions (the throwing one) should be highlighted as preferred.
I think there's a difference between errors and exceptions. Exceptions shouldn't be used in all cases. Olaf

Olaf van der Spek wrote:
On Tue, Oct 27, 2009 at 7:47 PM, Andrey Semashev <andrey.semashev@gmail.com> wrote:
Why is it necessary to impose a single view on the language? Authors often give advice and situations demand certain concessions. Isn't it reasonable to accommodate many use cases? If you're too restrictive, you make C++ less appealing and users will choose other languages. Is that helpful? I wouldn't say that it would narrow the language in some way. You still get the same functionality, only error reporting mechanism is in question. Using exceptions for this purpose is, well... following the language spirit, so to say, while mandating a dual approach honors code diversity. I happened to support some code that used both exceptions and error codes for error reporting, and I must say it was a pain. I think, at least for educational purposes one form of functions (the throwing one) should be highlighted as preferred.
I think there's a difference between errors and exceptions. Exceptions shouldn't be used in all cases.
Then, perhaps, we should take a closer look at these errors. Does, for instance, failing to delete a file qualify as such non-exception error? Or failing to send data through a socket? IMHO, if an operation fails to fulfill its postconditions, it is an error that should be indicated with an exception. If, by the nature of the operation, the postconditions are allowed to fail (that is, it is normal for them to fail), then the postconditions are badly formed, and we are not speaking of an error in the first place.

2009/10/27 Andrey Semashev <andrey.semashev@gmail.com>:
Then, perhaps, we should take a closer look at these errors. Does, for instance, failing to delete a file qualify as such non-exception error?
Depends on the usage. If I'm removing a cache file, it's plausible that it doesn't exist, and it's easier (less to type), faster (fewer operations to run), and more correct (due to race conditions) to just delete it than to guard it with an existence check.

Scott McMurray wrote:
2009/10/27 Andrey Semashev <andrey.semashev@gmail.com>:
Then, perhaps, we should take a closer look at these errors. Does, for instance, failing to delete a file qualify as such non-exception error?
Depends on the usage. If I'm removing a cache file, it's plausible that it doesn't exist, and it's easier (less to type), faster (fewer operations to run), and more correct (due to race conditions) to just delete it than to guard it with an existence check.
As I said in my another post, it depends on how postconditions are formed. If "the file does not exist" is the postcondition, I don't see why it should throw in the case you described.

2009/10/27 Andrey Semashev <andrey.semashev@gmail.com>:
As I said in my another post, it depends on how postconditions are formed. If "the file does not exist" is the postcondition, I don't see why it should throw in the case you described.
So in some cases, it's useful to allow for wider semantics, with a code indicating the result -- in this case, whether the file was actually removed. It's a rather straight-forward expansion of that idea to functions that never throw and thus return error_codes.

Andrey Semashev wrote:
I wouldn't say that it would narrow the language in some way. You still get the same functionality, only error reporting mechanism is in question. Using exceptions for this purpose is, well... following the language spirit, so to say, while mandating a dual approach honors code diversity. I happened to support some code that used both exceptions and error codes for error reporting, and I must say it was a pain. I think, at least for educational purposes one form of functions (the throwing one) should be highlighted as preferred. Maybe I missed something, but the subject still says 'filesystem'. And especially in that domain it's often that an error is not exceptional, e.g. 'file not found' or 'EAGAIN'. And errors that aren't exceptional shouldn't be reported and handled by exception throwing (and catching). What is exceptional and what not depends on the actual application, hence the two different forms.
Detlef

Detlef Vollmann wrote:
Andrey Semashev wrote:
I wouldn't say that it would narrow the language in some way. You still get the same functionality, only error reporting mechanism is in question. Using exceptions for this purpose is, well... following the language spirit, so to say, while mandating a dual approach honors code diversity. I happened to support some code that used both exceptions and error codes for error reporting, and I must say it was a pain. I think, at least for educational purposes one form of functions (the throwing one) should be highlighted as preferred. Maybe I missed something, but the subject still says 'filesystem'. And especially in that domain it's often that an error is not exceptional, e.g. 'file not found' or 'EAGAIN'. And errors that aren't exceptional shouldn't be reported and handled by exception throwing (and catching). What is exceptional and what not depends on the actual application, hence the two different forms.
I had experience with Boost.Filesystem, but I never had a single case when I needed an error code instead of an exception. So, unless I'm missing something, filesystem ops are better suited for exceptions than ASIO, that was claimed otherwise earlier in the thread. What I'm trying to say is that I think that if in particular case an exception is not desired, then this particular operation is not defined properly.

Andrey Semashev wrote:
I had experience with Boost.Filesystem, but I never had a single case when I needed an error code instead of an exception. So, unless I'm missing something, filesystem ops are better suited for exceptions than ASIO, that was claimed otherwise earlier in the thread. What I'm trying to say is that I think that if in particular case an exception is not desired, then this particular operation is not defined properly.
I don't know what kind of code you write, but I'll bet that it doesn't represent all of the needs of all of the different programmers who might use asio for their own purposes. Thus I don't think you can claim that exceptions are better than error codes in this domain just because you've never wanted error codes. I would also like to point out that you can trivially wrap an error code-based API with a throwing API that checks the error code and throws if an error occurred. Thus, if only one form is to be provided, and some users want error codes and some want exceptions, the error code version should be provided by the API. (If there are many users on each side, the API should probably provide both versions, probably by doing this kind of wrapping.) This is similar to how std::vector provides an unchecked operator[] -- you can build a safe facility (at()) on top of a fast one, but not the other way around. Since some users want speed and some users want safety, the library makes the flexible one the default, but provides both. --Jeffrey Bosboom

Andrey Semashev wrote:
Stewart, Robert wrote:
Andrey Semashev wrote:
Perhaps, we could mark the non-throwing overloads as deprecated in the Standard? Like strstreams, they are there but generally throwing overloads are more preferred.
Why is it necessary to impose a single view on the language? Authors often give advice and situations demand certain concessions. Isn't it reasonable to accommodate many use cases? If you're too restrictive, you make C++ less appealing and users will choose other languages. Is that helpful?
I wouldn't say that it would narrow the language in some way.
It doesn't narrow the language per se, but the standard library is considered part of C++ and will make the language less broadly appealing if too restrictive.
You still get the same functionality, only error reporting mechanism is in question. Using exceptions for this purpose is, well... following the language spirit, so to say, while mandating a dual approach honors code
I use exceptions a great deal. I have nothing against them. When appropriate, they make things much nicer. However, there are real use cases, some already posted, in which exceptions are too costly, while for typical usage they are exactly appropriate. You can choose just one or the other, alienating different groups, or you can provide both. C++ includes, by reference, the C standard library, too. Thus, all of those error code returning functions are considered part of the language. For example, you wouldn't want reading from a socket to throw an exception when no character is available if working over a dial-up connection or slow WAN because delays are certain. Furthermore, you can look at things in the C++ standard library and find error returns, too. Thus, it is wrong to suggest that exceptions are in the spirit of C++ while error returns are not. Both approaches have their place and should be applied wisely.
diversity. I happened to support some code that used both exceptions and error codes for error reporting, and I must say it was a pain. I think,
Perhaps the code you used was inconsistent in its use of exceptions versus return codes, perhaps the philosophy was poorly documented, or perhaps your bias against return codes made the problem worse than it really was. Your anecdote leaves little room for speculation beyond this.
at least for educational purposes one form of functions (the throwing one) should be highlighted as preferred.
By all means, write books and tutorials, and otherwise teach newcomers to use the exception-based interfaces. Until one understands the language well enough, and has been programming long enough, one can't judge the relative merits of return codes and exceptions to make a wise choice. However, that doesn't mean exceptions should be proffered as the one true way of C++ error reporting. Those that do understand, and have specific performance requirements, should be able to choose to forego the convenience of exceptions, and the safety of not being able to ignore them, when required. The library author must consider whether each library function should throw an exception, return an error code, or provide both options. During review, others may have differing opinions which may lead to rethinking the initial choice. Eventually, a library error handling philosophy will emerge and will inform the author for new functions as well as the library's users to know what to expect in each case. In Boost, lacking any coding guidelines for error handling, you can expect different libraries to follow different philosophies. In the C++ standard, you should expect consistency throughout. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

On Wed, Oct 28, 2009 at 8:47 AM, Stewart, Robert <Robert.Stewart@sig.com> wrote:
Until one understands the language well enough, and has been programming long enough, one can't judge the relative merits of return codes and exceptions to make a wise choice.
I understand the language pretty well, and have definitely been programming long enough, and I still argue with myself what way is best. And I suspect, in some zen-like way, this means I've reached, uhh... error handling nirvana? Unfortunately.
In Boost, lacking any coding guidelines for error handling, you can expect different libraries to follow different philosophies. In the C++ standard, you should expect consistency throughout.
Since Boost attempts to be "possibly standard", I suppose we should attempt to be consistent? Tony

Gottlob Frege wrote:
On Wed, Oct 28, 2009 at 8:47 AM, Stewart, Robert <Robert.Stewart@sig.com> wrote:
In Boost, lacking any coding guidelines for error handling, you can expect different libraries to follow different philosophies. In the C++ standard, you should expect consistency throughout.
Since Boost attempts to be "possibly standard", I suppose we should attempt to be consistent?
That's certainly laudable, but it requires someone to create a coding guideline and for there to be sufficiently broad acceptance of it. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

On Wed, Oct 28, 2009 at 10:59 AM, Stewart, Robert <Robert.Stewart@sig.com> wrote:
Gottlob Frege wrote:
On Wed, Oct 28, 2009 at 8:47 AM, Stewart, Robert <Robert.Stewart@sig.com> wrote:
In Boost, lacking any coding guidelines for error handling, you can expect different libraries to follow different philosophies. In the C++ standard, you should expect consistency throughout.
Since Boost attempts to be "possibly standard", I suppose we should attempt to be consistent?
That's certainly laudable, but it requires someone to create a coding guideline and for there to be sufficiently broad acceptance of it.
"Aye, there's the rub." - Scotty, Star Trek. . . . I mean, that Shakespeare guy, from "To be or not to be..." but said in a Scotty (James Doohan) voice in my head. Tony

"David Bergman" <David.Bergman@bergmangupta.com> wrote in message news:7D589D40-2CB8-4B3A-9805-37BA6451E9C9@bergmangupta.com...
There is no official recommendation for the language in-between EC++ and C++ - C++ minus exception handling - AFAIK, but it is no secret that Boost is targeting that "language" as well, and also C++/CLI to some extent.
From what I understand the std library relies on exceptions: std::vector does not provide any method: bool wasSuccessfulConstructed(void) const. So why does boost need to support something like this?

2009/10/27 Peter Foelsche <peter_foelsche@agilent.com>:
So why does boost need to support something like this?
Perhaps for the same reason that there's no way to have std::fstream's constructor throw? For the same reason that std::fstream.is_open exists?

On Tue, Oct 27, 2009 at 9:44 AM, Stewart, Robert <Robert.Stewart@sig.com>wrote:
Peter Foelsche wrote:
"Beman Dawes" <bdawes@acm.org> wrote in message news:a61d44020910200815kedf3976t6e96a67e2f453271@mail.gmail.com...
A POSIX sub-group is looking at C++ bindings for POSIX.
They are talking about a filesystem library binding at least loosely based on Boost.System, Boost.Filesystem, and C++ TR2.
In looking at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2838.html, "Library Support for Hybrid Error Handling (Rev 2)", they are concerned about specifying hybrid error handling like this:
What is the sense of a C++ interface, which does not throw on error?
Others noted embedded environments -- very important today -- but let's look at a broader case. Throwing an exception is extremely expensive for many reasons. Some applications encounter errors regularly and often due to the nature of their environment or context. Such applications, if errors were reported using exceptions, would have high or widely varying latencies and generally sluggish performance. If errors are relatively infrequent, then the cleanliness of writing code without error checking at every turn, and the zero or near zero overhead of exception handling code when no exceptions are raised, means using exceptions is nearly ideal. Eventually, however, there's a threshhold at which the frequency of exceptions, given the cost to throw them when they do occur, overwhelms the processing time. In that case, exceptions are a problem, not the solution.
Exactly. To put a number on the cost of using exceptions as a reporting mechanism, I've heard Bjarne Stroustrup say that measured experiments put exceptions as 1000 times as expensive as other return mechanisms, at least with some compilers. Another problem with exceptions is that when errors are the norm that must be handled immediately, code becomes to littered with try/catch blocks as to become unreadable and unmaintainable. These problems with exceptions aren't an issue in most C++ applications. But code dealing with low level I/O (networking, file systems) is at least one area where a mechanism other than exceptions is a necessity. That's what Rob is pointing out.
I think meanwhile (this is 2009) we should be over the "I hate C++ Exception Handling" thinking.
Perhaps there's room for other opinions on the use of exceptions now that we've moved beyond that phase and the "Exceptions are always the error handling scheme of choice in C++" phase?
This error_code scheme allows one to choose whether to get an exception or not. Thus, one chooses when the overhead of throwing exceptions is acceptable and when not. Surely that's not controversial.
One would hope not, since boost::error_code is part of C++0x and is already shipping with several standard library implementations. Thanks, --Beman

"Beman Dawes" <bdawes@acm.org> wrote in message news:a61d44020910200815kedf3976t6e96a67e2f453271@mail.gmail.com... ...
"Library Support for Hybrid Error Handling (Rev 2)", they are concerned about specifying hybrid error handling like this:
void f(error_code& ec=throws());
They would rather see it specified like this:
void f(error_code* ec=0); ...
i just wanted to make a proposal on a very related subject (an expension/generalization of the [system] error_code concept) so i'll post it here instead of starting a new thread: one of the 'selling points' of exceptions is that they, unlike error return codes, cannot be (unintentionally) ignored/forgotten... well...we could 'smarten' our error codes into error objects that 'complain' if they were not 'inspected' before they are destroyed... ...the 'complaint' method can be made a matter of policy...assert, throw, log ... so if we have an error object wrapper like this: template <class ActualError> class error { public: error( ActualError const & actual_error ) : actual_error_( actual_error ), inspected_( false ) {} ~error() ( if ( !inspected ) throw actual_error_; ) operator ActualError & () { inspected_ = true; return actual_error_; } private: ActualError actual_error_; bool inspected_; } we could trivially modify otherwise throwing-but-void-returning functions to now return errors wrapped in error<>...then the functions themselves would always be no-throw and the calling code would decide whether to let errors become exceptions or inspect the results right after the call... ...some usual cases could be made more readable with standardized global inspecting functions like: verify( someFuncThatReturnsError(...) ); that would assert that the call indeed succeeded as expected (and in release only 'touch' the object to prevent the throw)... and things like that... the throwing destructor should be safe in this case because error<>, if used correctly, should always be a temporary and as such can never be destructed as a consequence of some other exception being thrown... -- "That men do not learn very much from the lessons of history is the most important of all the lessons of history." Aldous Huxley

On Tue, Oct 27, 2009 at 8:32 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Beman Dawes" <bdawes@acm.org> wrote in message news:a61d44020910200815kedf3976t6e96a67e2f453271@mail.gmail.com...
i just wanted to make a proposal on a very related subject (an expension/generalization of the [system] error_code concept) so i'll post it here instead of starting a new thread:
one of the 'selling points' of exceptions is that they, unlike error return codes, cannot be (unintentionally) ignored/forgotten...
well...we could 'smarten' our error codes into error objects that 'complain' if they were not 'inspected' before they are destroyed... ...the 'complaint' method can be made a matter of policy...assert, throw, log ...
Meyers or Alexandrescu or ___? proposed something similar once. Yet I can't find the article... Tony

"Gottlob Frege" <gottlobfrege@gmail.com> wrote in message news:97ffb310910280746p3822bbafgaf6ce85f3945ef87@mail.gmail.com...
Meyers or Alexandrescu or ___? proposed something similar once. Yet I can't find the article...
"shoot"...that would probably mean that a "show stopper" flaw was probably found in the idea (considering it was not actually used/implemented anywhere...not that i know of atleast...)... -- "That men do not learn very much from the lessons of history is the most important of all the lessons of history." Aldous Huxley

Domagoj Saric wrote:
~error() ( if ( !inspected ) throw actual_error_; ) This was discussed in the POSIX/C++ meeting 10 days ago, and was considered to be a good idea. Unfortunately, in the current C++ working paper, we have in 17.6.4.10 Restrictions on exception handling [res.on.exception.handling]: "4 Destructor operations defined in the C++ standard library shall not throw exceptions. "
Detlef

On Wed, Oct 28, 2009 at 12:40 PM, Detlef Vollmann <dv@vollmann.ch> wrote:
Domagoj Saric wrote:
~error() ( if ( !inspected ) throw actual_error_; )
This was discussed in the POSIX/C++ meeting 10 days ago, and was considered to be a good idea. Unfortunately, in the current C++ working paper, we have in 17.6.4.10 Restrictions on exception handling [res.on.exception.handling]: "4 Destructor operations defined in the C++ standard library shall not throw exceptions. "
A library should either throw when the error is detected or not. If it doesn't, the user might still throw, but the *library* throwing later seems a very bad idea. Not to mention the issue that throwing in a destructor can end up calling abort(). Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

"Emil Dotchevski" <emildotchevski@gmail.com> wrote in message news:c72e33ce0910281332m5ec6d444gf249609963661587@mail.gmail.com...
On Wed, Oct 28, 2009 at 12:40 PM, Detlef Vollmann <dv@vollmann.ch> wrote:
Domagoj Saric wrote:
~error() ( if ( !inspected ) throw actual_error_; )
This was discussed in the POSIX/C++ meeting 10 days ago, and was considered to be a good idea. Unfortunately, in the current C++ working paper, we have in 17.6.4.10 Restrictions on exception handling [res.on.exception.handling]: "4 Destructor operations defined in the C++ standard library shall not throw exceptions. "
A library should either throw when the error is detected or not. If it doesn't, the user might still throw, but the *library* throwing later seems a very bad idea. Not to mention the issue that throwing in a destructor can end up calling abort().
i mentioned the latter 'issue' already in the first post... generally both points seem to me like non-issues because they cannot become issues unintentionally... both can come into play _only_ if the user converts the temporary return object into a local scoped object/variable...which, as far as i know, you cannot do 'by accident'/unintentionally...you have to be verbose about it...(although, ironically the new auto makes it easier for you to do "the wrong thing"...but still not easy enough that you can do it by a 'non conscious mistake')... if you just ignore the return...the function will appear to throw just as if it threw 'from within'...if you inspect it it 'magically' starts to behave as if it does not throw but returns an error code... ..._only_ if you save the returned object into a local scoped variable _and_ do not inspect it can the issues of "library after throw" and "abort on exception in destructor during unwind" come into play... only/one of the draw backs i can see here is a certain amount of bloat, for those that would mostly choose the throw option (not to inspect the error ), compared to the case where the throw would come from within because now the throwing and 'if' logic would be duplicated into every caller function (instead of just being in one place...the function that actually 'produces' the error)... -- "That men do not learn very much from the lessons of history is the most important of all the lessons of history." Aldous Huxley

On Wed, Oct 28, 2009 at 3:46 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Emil Dotchevski" <emildotchevski@gmail.com> wrote in message news:c72e33ce0910281332m5ec6d444gf249609963661587@mail.gmail.com...
On Wed, Oct 28, 2009 at 12:40 PM, Detlef Vollmann <dv@vollmann.ch> wrote:
Domagoj Saric wrote:
~error() ( if ( !inspected ) throw actual_error_; )
This was discussed in the POSIX/C++ meeting 10 days ago, and was considered to be a good idea. Unfortunately, in the current C++ working paper, we have in 17.6.4.10 Restrictions on exception handling [res.on.exception.handling]: "4 Destructor operations defined in the C++ standard library shall not throw exceptions. "
A library should either throw when the error is detected or not. If it doesn't, the user might still throw, but the *library* throwing later seems a very bad idea. Not to mention the issue that throwing in a destructor can end up calling abort().
i mentioned the latter 'issue' already in the first post... generally both points seem to me like non-issues because they cannot become issues unintentionally... both can come into play _only_ if the user converts the temporary return object into a local scoped object/variable...which, as far as i know, you cannot do 'by accident'/unintentionally...you have to be verbose about it...(although, ironically the new auto makes it easier for you to do "the wrong thing"...but still not easy enough that you can do it by a 'non conscious mistake')...
It
if you just ignore the return...the function will appear to throw just as if it threw 'from within'...if you inspect it it 'magically' starts to behave as if it does not throw but returns an error code...
..._only_ if you save the returned object into a local scoped variable _and_ do not inspect it can the issues of "library after throw" and "abort on exception in destructor during unwind" come into play...
only/one of the draw backs i can see here is a certain amount of bloat, for those that would mostly choose the throw option (not to inspect the error ), compared to the case where the throw would come from within because now the throwing and 'if' logic would be duplicated into every caller function (instead of just being in one place...the function that actually 'produces' the error)...
Assuming that there is an agreement that the user *knows* if she wants an exception or an error code, why not provide two functions: one that returns an error code, and another one that calls the first one and throws on error?
-- "That men do not learn very much from the lessons of history is the most important of all the lessons of history." Aldous Huxley
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

"Emil Dotchevski" <emildotchevski@gmail.com> wrote in message news:c72e33ce0910281601i358d695dw88cd851b001d39ae@mail.gmail.com...
Domagoj Saric wrote: i mentioned the latter 'issue' already in the first post... generally both points seem to me like non-issues because they cannot become issues unintentionally... both can come into play _only_ if the user converts the temporary return object into a local scoped object/variable...which, as far as i know, you cannot do 'by accident'/unintentionally...you have to be verbose about it...(although, ironically the new auto makes it easier for you to do "the wrong
On Wed, Oct 28, 2009 at 12:40 PM, Detlef Vollmann <dv@vollmann.ch> wrote: thing"...but still not easy enough that you can do it by a 'non conscious mistake')...
It
sorry is "It" an acronym i'm not familiar with or you just forgot to finish your sentence? ;)
Assuming that there is an agreement that the user *knows* if she wants an exception or an error code,
well i'd say it's pretty obvious that the user knows...in the sense that you can/have no other option but to assume that the user knows...because as a user you are always forced to either learn the options of a tool that you use (in order to be able to use it at all) _or_, _if_ your tool provides some defaults you have the option of sticking to the defaults... ...same situation here...if the user knows his/hers preferences great, if not than the default policy will be "in charge"... what's the difference between that and the status quo? you also currently have functions that throw, that return an error or do both or some fourth wild thing...as a user you always have the option of either ignoring all that and live in some fanatasy world and "create bad software that works only on every other sunny thursday" or to "know your stuff"... ...i must admit not to understand this point...its like worrying whether the user will know that new throws or returns null or which new and malloc handler to use...it doesn't seem like something to base design decisions on...in this day and age you can still find loads of people and libraries that still do not use new 'right'...(e.g. pick any of your favorite gui library...usually the bigger/bloatier and more popular the crappier code...)...yet that is not the reason why to ashew new and go back to malloc...
why not provide two functions: one that returns an error code, and another one that calls the first one and throws on error?
because that seems more complicated and less powerfull and configurable (to me, from the current perspective)... - you'd have to write and maintain a 'tremendous' amount of boilerplate code (with an added overload for every existing function and overload)... - the only way to configure the behaviour (choose a policy, what i mentioned in the first post) would be using macros...plus you still wouldn't have a mechanism that asserts that you checked the return of an overload that does not throw but returns an error code... -- "That men do not learn very much from the lessons of history is the most important of all the lessons of history." Aldous Huxley

Domagoj Saric wrote:
"Emil Dotchevski" <emildotchevski@gmail.com> wrote in message news:c72e33ce0910281332m5ec6d444gf249609963661587@mail.gmail.com...
On Wed, Oct 28, 2009 at 12:40 PM, Detlef Vollmann <dv@vollmann.ch> wrote:
Domagoj Saric wrote:
~error() ( if ( !inspected ) throw actual_error_; )
A library should either throw when the error is detected or not. If it doesn't, the user might still throw, but the *library* throwing later seems a very bad idea. Not to mention the issue that throwing in a destructor can end up calling abort().
if you just ignore the return...the function will appear to throw just as if it threw 'from within'...if you inspect it it 'magically' starts to behave as if it does not throw but returns an error code...
From a debugging perspective, the exception will be thrown at the wrong point.
..._only_ if you save the returned object into a local scoped variable _and_ do not inspect it can the issues of "library after throw" and "abort on exception in destructor during unwind" come into play...
The complexity of this magical behavior, the problem with throwing in the caller rather than at the point of error, the overhead of checking to see whether to throw at each call site, and the danger of throwing in the destructor during stack unwinding, makes overloading each affected function a pleasant alternative. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

Domagoj Saric wrote:
On Wed, Oct 28, 2009 at 12:40 PM, Detlef Vollmann <dv@vollmann.ch> wrote:
Domagoj Saric wrote:
~error() ( if ( !inspected ) throw actual_error_; ) A library should either throw when the error is detected or not. If it doesn't, the user might still throw, but the *library* throwing later seems a very bad idea. Not to mention the issue that throwing in a destructor can end up calling abort(). if you just ignore the return...the function will appear to
"Emil Dotchevski" <emildotchevski@gmail.com> wrote in message news:c72e33ce0910281332m5ec6d444gf249609963661587@mail.gmail.com... throw just as if it threw 'from within'...if you inspect it it 'magically' starts to behave as if it does not throw but returns an error code...
From a debugging perspective, the exception will be thrown at the wrong point. I'm not so sure about this argument. What you would probably throw is not the original exception, but an exception objects of some type like 'unhandled_error'
Stewart, Robert wrote: that has inside the original exception data. This was discussed with a bit different perspective: For a lot of system level calls, you could get quite a number of different error codes. Some of them are not really exceptional errors (e.g. EAGAIN) in a lot of contexts. But it's up to the application what error codes represent exceptional errors and which don't. So the call would be something like 'device.read(error_object, ...)' and error_object would have member functions to query for error codes, and the destructor would throw, if error_object would contain an error code that was not queried for. I believe this is a viable approach. But the basic problem of throwing exceptions from destructors exists, and is IMO a major flaw of how exception handling works in C++, but I don't think that this will change. Detlef

Detlef Vollmann wrote:
Stewart, Robert wrote:
From a debugging perspective, the exception will be thrown at the wrong point.
What you would probably throw is not the original exception, but an exception objects of some type like 'unhandled_error' that has inside the original exception data.
That's fine, but then an exception isn't thrown at the point where the error was detected, so the stack frame giving context for the error is lost.
For a lot of system level calls, you could get quite a number of different error codes. Some of them are not really exceptional errors (e.g. EAGAIN) in a lot of contexts. But it's up to the application what error codes represent exceptional errors and which don't.
That's an interesting notion. I'm sure those in this discussion that want exceptions in all cases would expect different exception types to represent some of the types of errors that can occur. Your approach will collapse them into a single type.
So the call would be something like 'device.read(error_object, ...)' and error_object would have member functions to query for error codes, and the destructor would throw, if error_object would contain an error code that was not queried for.
One must check for each possible error individually in order to avoid an exception? That doesn't seem beneficial. There are many cases in which one wants to check for specific errors to handle locally and to throw an exception for the rest or just return a failure indication -- perhaps after logging the problem. Thus, there should be a means to simply query generally for failure and have that prevent throwing an exception.
But the basic problem of throwing exceptions from destructors exists,
Right.
and is IMO a major flaw of how exception handling works in C++, but I don't think that this will change.
No, that isn't likely to change. It would be a major refactoring of the mechanisms and concepts. Ideally, what we want is a compile-time failure if the error_code isn't checked. After all, the point is that we want to be sure that the caller gets an exception or checks for failure. (We can't verify that the caller does anything appropriate in either case, of course. ;-) That requires compiler support and there's precious little time to add that to C++0x, if any. Therefore, we'll just have to make the best of things and, perhaps, guide the LWG in how best to use error_code. ~error_code() could test for a pending exception before throwing an exception. If there is a pending exception, that means the stack is being unwound and the error_code shouldn't aggravate the situation by throwing its own. Otherwise, it can throw in its destructor, right? Given that the caller expressly asked for the function to throw no exceptions but populate an error_code, it isn't too much to expect that caller to check for an error, even when the error is to be ignored. (Indeed, error_code could provide a constructor argument or member function indicating that the caller wishes to ignore the error.) That still means that error_code is "magical," but if those not ready to understand its use simply call overloads that throw rather than take an error_code instance, there's no undue complication. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

2009/10/29 Stewart, Robert <Robert.Stewart@sig.com>:
~error_code() could test for a pending exception before throwing an exception. If there is a pending exception, that means the stack is being unwound and the error_code shouldn't aggravate the situation by throwing its own. Otherwise, it can throw in its destructor, right? Given that the caller expressly asked for the function to throw no exceptions but populate an error_code, it isn't too much to expect that caller to check for an error, even when the error is to be ignored. (Indeed, error_code could provide a constructor argument or member function indicating that the caller wishes to ignore the error.)
FWIW: "Unfortunately, I do not know of any good and safe use for std::uncaught_exception. My advice: Don't use it." ~ http://www.gotw.ca/gotw/047.htm

Scott McMurray wrote:
2009/10/29 Stewart, Robert <Robert.Stewart@sig.com>:
~error_code() could test for a pending exception before throwing an exception. If there is a pending exception, that means the stack is being unwound and the error_code shouldn't aggravate the situation by throwing its own. Otherwise, it can throw in its destructor, right? Given that the caller expressly asked for the function to throw no exceptions but populate an error_code, it isn't too much to expect that caller to check for an error, even when the error is to be ignored. (Indeed, error_code could provide a constructor argument or member function indicating that the caller wishes to ignore the error.)
FWIW: "Unfortunately, I do not know of any good and safe use for std::uncaught_exception. My advice: Don't use it." ~ http://www.gotw.ca/gotw/047.htm
Yes, I was aware of those issues. However, the point of the exception here is to flag that the client failed to do what should have been done: check for errors. To be helpful, the original error information is passed along, but that is most helpful, in my mind, to help identify the place where the failure to check occurred. That the exception won't be thrown in certain contexts doesn't mean it isn't useful in the rest. One might argue that clients will try to rely on the exception since it contains the error information, so perhaps not transmitting that information with the "unhandled error" exception is wiser. I briefly considered mentioning asserting in my last post, but chose not to just to focus on the other ideas. To throwing an exception when there isn't a pending exception, we can assert, in debug builds anyway, when the error isn't checked. Thus, the developer should get an assertion failure pointing to the error_code that wasn't checked. If the assertion is disabled (non-debug build, say), the application will get an exception in most circumstances. The point is to make it unwise to fail to check an error_code for errors. Add to that the use of overloads to distinguish throwing from non-throwing (but error_code populating) functions and its a pretty decent mechanism, don't you think? _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

2009/10/29 Stewart, Robert <Robert.Stewart@sig.com>
Yes, I was aware of those issues. However, the point of the exception here is to flag that the client failed to do what should have been done: check for errors. To be helpful, the original error information is passed along, but that is most helpful, in my mind, to help identify the place where the failure to check occurred. That the exception won't be thrown in certain contexts doesn't mean it isn't useful in the rest.
In other words, a programming error (failure to check an error return) is detected. This is exactly the reason to use assert, not exceptions. It is hard enough to do this kind of mechanism correctly. For instance, if you look at the code as posted, assignment doesn't have the correct semantics, and is hard to get correct without reference counting, which would put its overhead in the realm of shared_ptr (a heap allocation for the reference count). I've done this kind of thing in very limited circumstances (assert if the error code isn't checked), and I ended up with a class that was "Moveable" (in the same way that auto_ptr is "Moveable", as this is pre-C++0x code) but not Assignable. Now add in the complication of throwing unless there is a throw in progress (if you have an example of how to do this, please post a link to working code which does it), and you are coming up with a mechanism that is both hard to use correctly and hard to reason about. I briefly considered mentioning asserting in my last post, but chose not to
just to focus on the other ideas. To throwing an exception when there isn't a pending exception, we can assert, in debug builds anyway, when the error isn't checked. Thus, the developer should get an assertion failure pointing to the error_code that wasn't checked. If the assertion is disabled (non-debug build, say), the application will get an exception in most circumstances.
What good does that do? I can't think of any circumstance where I'd want to not assert when I detect a programming error (where "assert" is short hand for the more general "put the program back into a known state. On normal programs, just abort; on more safety critical programs, that is an exercise left to the programmer" kind of thing). -- Nevin Liber <mailto:nevin@eviloverlord.com> (847) 691-1404 Sent from Chicago, IL, United States

Nevin Liber wrote:
2009/10/29 Stewart, Robert <Robert.Stewart@sig.com>
Yes, I was aware of those issues. However, the point of the exception here is to flag that the client failed to do what should have been done: check for errors. To be helpful, the original error information is passed along, but that is most helpful, in my mind, to help identify the place where the failure to check occurred. That the exception won't be thrown in certain contexts doesn't mean it isn't useful in the rest.
In other words, a programming error (failure to check an error return) is detected.
That's how I understand what's been proposed.
This is exactly the reason to use assert, not exceptions.
Certainly, assertions are the best tool, but not everyone tests debug builds or covers all branches when testing them. You could argue that calling std::abort() or std::terminate() is a better choice when the assertion is compiled out.
It is hard enough to do this kind of mechanism correctly.
It would be done once by a library.
Now add in the complication of throwing unless there is a throw in progress (if you have an example of how to do this, please post a link to working code which does it)
It's simple: if (error-not-checked && !std::uncaught_exception()) { throw something; }
, and you are coming up with a mechanism that is both hard to use correctly and hard to reason about.
It isn't so hard, really. If you call a function that populates an error_code passed to the function by non-const reference or pointer, and you fail to inspect that error_code to see whether there was an error, that error_code will do nasty things to your program at runtime. If using a debug build of the library, you'll get an assertion. If not, the library will call std::abort() (or whatever) or throw some exception.
To throwing an exception when there isn't a pending exception, we can assert, in debug builds anyway, when the error isn't checked. Thus, the developer should get an assertion failure pointing to the error_code that wasn't checked. If the assertion is disabled (non-debug build, say), the application will get an exception in most circumstances.
What good does that do? I can't think of any circumstance where I'd want to not assert when I detect a programming error
assert is a macro that is typically disabled in non-debugging builds.
(where "assert" is short hand for the more general "put the program back into a known state. On normal
That is not what I mean by "assert" and I've never heard it defined as you have here.
programs, just abort; on more safety critical programs, that is an exercise left to the programmer" kind of thing).
One can imagine error_code::set_unhandled_error_handler() to register a handler to customize what occurs when a programmer fails to check an error. If no handler is registered, the behaviors mentioned above could provided by default. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

On Thu, Oct 29, 2009 at 1:46 PM, Stewart, Robert <Robert.Stewart@sig.com> wrote:
It's simple:
if (error-not-checked && !std::uncaught_exception()) { throw something; }
http://www.gotw.ca/gotw/047.htm Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Thu, Oct 29, 2009 at 5:07 PM, Emil Dotchevski <emildotchevski@gmail.com> wrote:
On Thu, Oct 29, 2009 at 1:46 PM, Stewart, Robert <Robert.Stewart@sig.com> wrote:
It's simple:
if (error-not-checked && !std::uncaught_exception()) { throw something; }
I've read that article before. To me it only seemed applicable to destructors that actually did something, like a rollback. For an object that does nothing in its destructor, do you think Herb's arguments still apply? I'm not advocating either error checking approach, I'm just genuinely curious. But maybe that makes it offtopic... Regards, --Michael Fawcett

On Thu, Oct 29, 2009 at 2:20 PM, Michael Fawcett <michael.fawcett@gmail.com> wrote:
On Thu, Oct 29, 2009 at 5:07 PM, Emil Dotchevski <emildotchevski@gmail.com> wrote:
On Thu, Oct 29, 2009 at 1:46 PM, Stewart, Robert <Robert.Stewart@sig.com> wrote:
It's simple:
if (error-not-checked && !std::uncaught_exception()) { throw something; }
I've read that article before. To me it only seemed applicable to destructors that actually did something, like a rollback. For an object that does nothing in its destructor, do you think Herb's arguments still apply?
The point is that a destructor could call a function that returns this sneaky error code object, and end up throwing an exception. You can argue that this is a bug, but that's exactly why it is evil -- for anything but a trivial toy example, such code can't reasonably be tested because it is very difficult to reproduce the conditions that could possibly lead to abort(). Why not just pick a behavior -- throw on error, or don't throw on error -- whichever is correct? Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

"Emil Dotchevski" <emildotchevski@gmail.com> wrote in message news:c72e33ce0910291442k3a989264v25a367c19a4cdc05@mail.gmail.com...
On Thu, Oct 29, 2009 at 2:20 PM, Michael Fawcett <michael.fawcett@gmail.com> wrote:
On Thu, Oct 29, 2009 at 5:07 PM, Emil Dotchevski <emildotchevski@gmail.com> wrote:
On Thu, Oct 29, 2009 at 1:46 PM, Stewart, Robert <Robert.Stewart@sig.com> wrote:
It's simple:
if (error-not-checked && !std::uncaught_exception()) { throw something; }
I've read that article before. To me it only seemed applicable to destructors that actually did something, like a rollback. For an object that does nothing in its destructor, do you think Herb's arguments still apply?
The point is that a destructor could call a function that returns this sneaky error code object, and end up throwing an exception. You can argue that this is a bug, but that's exactly why it is evil -- for anything but a trivial toy example, such code can't reasonably be tested because it is very difficult to reproduce the conditions that could possibly lead to abort().
imho gotw-047 does not apply here: - the "unsound" objection does not apply here because with "smart_error_codes" it is not the callee (T::~T in the example) that decides whether to throw or not...it is the caller...and the caller is the (U) destructor (i.e. the writer of the destructor) that knows that it does not want throw...and with "smart_error_codes" it does not have to use try-catch to swallow/handle the exception it simply "inspects" the returned "smart_error_code" and thus both disables exceptions and handles a possible error condition... (maybe i shoudn't have used the exact example from gotw-047 because it uses a destructor in a destructor and destructors cannot return values...but i hope the argument is still clear) - the "unmoral" objection does not apply here because the caller is not forced to handle both flavours of error reporting...the user is given the "power" to choose which method suits best...and it also forces the programmers to check for errors, whichever method is used ;) imho your "evil" objection also does not apply because if a "smart error code" object is "sneaky" then so is the T object in the gotw-047 example...in other words any function that can possibly throw falls into the category of a "sneaky object" (because it can possibly throw in a destructor and cause abort() to be called...and because it can only possibly throw it is also not be "reasonably tested")... ...i would actually claim quite to the contrary...the "smart error code" approach would actually give you a simpler way to disable exceptions in a destructor while still handling errors...
Why not just pick a behavior -- throw on error, or don't throw on error -- whichever is correct?
exactly...that's what a "smartened error code" gives you...pick a behavior on a call by call basis ;) -- "That men do not learn very much from the lessons of history is the most important of all the lessons of history." Aldous Huxley

Emil Dotchevski wrote:
On Thu, Oct 29, 2009 at 1:46 PM, Stewart, Robert <Robert.Stewart@sig.com> wrote:
It's simple:
if (error-not-checked && !std::uncaught_exception()) { throw something; }
We already addressed that in this thread. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

Detlef Vollmann wrote:
From a debugging perspective, the exception will be thrown at the wrong point. What you would probably throw is not the original exception, but an exception objects of some type like 'unhandled_error'
Stewart, Robert wrote: that has inside the original exception data.
That's fine, but then an exception isn't thrown at the point where the error was detected, so the stack frame giving context for the error is lost. From a pedantic point of view I could argue that the exception is that the error wasn't handled, and the context of that exception would be preserved. But I admit that the really interesting thing is where the original error occurred, and that is lost. But if we're talking about system calls (and this is what I'm talking about), then the exception would only be thrown at the point of the system call anyway. So if the system call returns a 'poisoned' error object that (possibly) throws at destruction, that shouldn't be far from the failing system call, so you don't loose much of
Stewart, Robert wrote: the context.
For a lot of system level calls, you could get quite a number of different error codes. Some of them are not really exceptional errors (e.g. EAGAIN) in a lot of contexts. But it's up to the application what error codes represent exceptional errors and which don't.
That's an interesting notion. I'm sure those in this discussion that want exceptions in all cases would expect different exception types to represent some of the types of errors that can occur. Your approach will collapse them into a single type. Separate exception objects are the old times. Now we have exceptions like regex_error, future_error or system_error, whose sole purpose is to wrap a lot of different errors into one exception.
So the call would be something like 'device.read(error_object, ...)' and error_object would have member functions to query for error codes, and the destructor would throw, if error_object would contain an error code that was not queried for.
One must check for each possible error individually in order to avoid an exception? That doesn't seem beneficial. There are many cases in which one wants to check for specific errors to handle locally and to throw an exception for the rest or just return a failure indication -- perhaps after logging the problem. Thus, there should be a means to simply query generally for failure and have that prevent throwing an exception. The idea is that you check for things that are not exceptional, and for everything else an error is thrown. But of course there would also be an equivalent for 'is_error_condition_enum'.
Ideally, what we want is a compile-time failure if the error_code isn't checked. After all, the point is that we want to be sure that the caller gets an exception or checks for failure. No, only non-exceptional "errors" should be checked, all others throw an exception. Especially in system level code, it's really the application that defines what errors are exceptional and what "errors" are to be expected.
~error_code() could test for a pending exception before throwing an exception. If there is a pending exception, that means the stack is being unwound and the error_code shouldn't aggravate the situation by throwing its own. Otherwise, it can throw in its destructor, right? In theory, yes. But that would violate a lot of exception safety guarantees.
Detlef

Detlef Vollmann wrote:
Stewart, Robert wrote:
Detlef Vollmann wrote:
From a debugging perspective, the exception will be thrown at the wrong point. What you would probably throw is not the original exception, but an exception objects of some type like 'unhandled_error'
Stewart, Robert wrote: that has inside the original exception data.
That's fine, but then an exception isn't thrown at the point where the error was detected, so the stack frame giving context for the error is lost.
From a pedantic point of view I could argue that the exception is that the error wasn't handled, and the context of that exception would be preserved. But I admit that the really interesting thing is where the original error occurred, and that is lost.
In this case, the developer indicated non-throwing error handling and then didn't manage that correctly. Until that's addressed, the rest is less important; once addressed, the rest will probably be correct (due to the addition of error handling code). Consequently, my debugging argument is weak.
For a lot of system level calls, you could get quite a number of different error codes. Some of them are not really exceptional errors (e.g. EAGAIN) in a lot of contexts. But it's up to the application what error codes represent exceptional errors and which don't.
That's an interesting notion. I'm sure those in this discussion that want exceptions in all cases would expect different exception types to represent some of the types of errors that can occur. Your approach will collapse them into a single type.
Separate exception objects are the old times.
If you say so.
Now we have exceptions like regex_error, future_error or system_error, whose sole purpose is to wrap a lot of different errors into one exception.
Those are design choices of certain libraries. That doesn't make the choices ubiquitous.
So the call would be something like 'device.read(error_object, ...)' and error_object would have member functions to query for error codes, and the destructor would throw, if error_object would contain an error code that was not queried for.
One must check for each possible error individually in order to avoid an exception? That doesn't seem beneficial.
There are many cases in which one wants to check for specific errors to handle locally and to throw an exception for the rest or just return a failure indication -- perhaps after logging the problem. Thus, there should be a means to simply query generally for failure and have that prevent throwing an exception.
You are mixing the two approaches that have been proposed thus far. Thus far, the idea has been to either throw an exception or deal with error codes. Thus, for your scenario, you must inspect the error_code object for errors. If you want exceptions, you must throw them in your code. If you fail to check for errors, the error_code object *might* be able to throw an exception to alert you to that programming error.
The idea is that you check for things that are not exceptional, and for everything else an error is thrown.
This is a new idea to this thread and I find it unwise.
Ideally, what we want is a compile-time failure if the error_code isn't checked. After all, the point is that we nt to be sure that the caller gets an exception or checks for failure.
No, only non-exceptional "errors" should be checked, all others throw an exception.
This is based upon your newly suggested idea. Given the basis of the previous discussion of this mechanism, a compile time failure would work fine, if it were possible.
Especially in system level code, it's really the application that defines what errors are exceptional and what "errors" are to be expected.
Exactly. Hence, application level code must inspect the error_code object to determine what occurred and decide whether to throw an exception. The application code must not check for some errors and then assume the error_code will throw some useful exception for the rest. As has been covered in this thread, one cannot count on a destructor throwing an exception when wanted and otherwise not. It is, therefore, unwise to design the mechanism on that foundation.
~error_code() could test for a pending exception before throwing an exception. If there is a pending exception, that means the stack is being unwound and the error_code shouldn't aggravate the situation by throwing its own. Otherwise, it can throw in its destructor, right?
In theory, yes. But that would violate a lot of exception safety guarantees.
Your notion of ~error_code() throwing an exception if one doesn't check for the actual error that occurred does the same. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

"Stewart, Robert" <Robert.Stewart@sig.com> wrote in message news:DF2E67F3D097004694C8428C70A3FD69046F55F756@msgbal516.ds.susq.com...
The idea is that you check for things that are not exceptional, and for everything else an error is thrown.
This is a new idea to this thread and I find it unwise.
as far as i understood the existing boost::error_code documentation this is actually exactly why the whole library exists...to enable exception-free handling of 'unwanted' but non-exceptional cases/situations... -- "That men do not learn very much from the lessons of history is the most important of all the lessons of history." Aldous Huxley

Detlef Vollmann wrote:
But the basic problem of throwing exceptions from destructors exists, and is IMO a major flaw of how exception handling works in C++, but I don't think that this will change.
FWIW, the language allows to work around this problem. You can use std::uncaught_exception to detect whether to throw exception in a destructor or not. Regarding the original idea of returning an object that would throw in its destructor, I don't see this problem at all, as this object can only be returned if there is no exception propagating. However, I can't say I'm in favor of this idea.

On 10/31/09 12:48, Andrey Semashev wrote:
Detlef Vollmann wrote:
But the basic problem of throwing exceptions from destructors exists, and is IMO a major flaw of how exception handling works in C++, but I don't think that this will change.
FWIW, the language allows to work around this problem. You can use std::uncaught_exception to detect whether to throw exception in a destructor or not. This was already discussed earlier in this thread. And the issue is not so much that uncaught_exception() doesn't always return what you want to know ("is it safe to throw?"), but the exception safety guarantees that break if a destructor throws.
Regarding the original idea of returning an object that would throw in its destructor, I don't see this problem at all, as this object can only be returned if there is no exception propagating. However, I can't say I'm in favor of this idea. I still somehow like it, but there are to many problems with it.
Detlef

"Detlef Vollmann" <dv@vollmann.ch> wrote in message news:4AE99A0F.3070809@vollmann.ch...
From a debugging perspective, the exception will be thrown at the wrong point. I'm not so sure about this argument. What you would probably throw is not the original exception, but an exception objects of some type like 'unhandled_error'
Stewart, Robert wrote: that has inside the original exception data.
hmm...this actually points out that i pretty much messed up in my first post/did not properly define neither the solution nor the problem it was trying to solve (actually mixed two solutions for two problems)... :: one problem is the problem of /unchecked return error/status codes/...which could, i think, be solved quite well with the proposed error_code object that asserts that it was inspected... [ throwing an exception in that case is "out of the question" "in my book"...that is by definition a programmer error...and those are checked with asserts...(although i wouldn't mind leaving a configuration option for those closer to the paranoid/defensive/corporate software world that would place a throw after the assert for NDEBUG builds)...ironically my first code snippet did just that...threw in case of an uninspected object even if no error actually occured ] :: the other problem is the reporting and handling of errors and "exceptional situations": there seems to be three schools here: - "do not use exceptions at all", which i think is unanimously regarded as flawed here so there's no need to waste time on it - "error codes are not-by-the book, outdated, uncool, unholy historical artefacts, always use exceptions" the boost::error_code documentation provides some good arguments against such a "fundamentalist" policy - that you sometimes actually need to know the result at the site of the call which would force you to use try-catch blocks making your code actually uglier/less readable than if error/status codes were used, in addition to your code being less efficient (both in terms of space and time)... ...i would expand on that by saying that it is not always possible to know which functionality falls into which category... ...for example, as you mentioned, the functions that return codes with semantics similar to EAGAIN would probably always fall into the category of "best reported, inspected and handled with error codes" category...but other situations might not be so clear cut, e.g. file IO or some special GUI operation failure would in most situations probably constitute unexpected (or "unhandlebale at the call site") situation thus falling into the "best reported, inspected and handled with exceptions" category, but not always: some already pointed out cases of temporary, cached or networked files...all in all most issues mentioned deal with system io calls...but imo it would be usefull if we could find a solution that would work "across the board"...i.e. an error reporting mechanism that could be used not only by low level system and io libraries but also by gui libraries, xml parsers, string, algorithm and conversion libraries and so on...that would thus bring the choice of whether to use exceptions or error codes to the widest possible audience in the widest possible context/number of applicable situations...it would no longer be the worry of the library writer which mechanism to use to report errors...the user would decide for him/herself at the very place of the call! for example if one uses lexical_cast<> deep in the bowels of some parser it would probably be "natural" to use a bad_cast exception to report an error to the outside world but if one uses lexical_cast<> to convert a string entered into a widget by a user into an int it would mostly be simpler to have a simple error code if the user entered an invalid string and issue a warning and retry "at the face of the place"... ...this brings us to the second part of the "equation"..efficiency... the lexical_cast<> example is perhaps bad because the current implementation uses std::streams and is thus incredibly inefficient... { on msvc 9.0 sp1 the single line boost::lexical_cast<int>( "321" ); caused 14 calls to new and 26 calls to EnterCriticalSection() (not to mention vtable initializations, virtual function calls, usage of locales...) the first time it is called, and 3 calls to new and 15 calls to EnterCriticalSection() on subsequent calls...and caused the binary to increase by 50 kB! ...which is imnho abhorrent... some perspective: http://kk.kema.at/files/kkrieger-beta.zip http://www.youtube.com/watch?v=3vzcMdkvPPg } so the overhead of one more exception and a try-catch block becomes not as relevant in comparison (and it can also throw bad_alloc, but this is a specific issue i will tackle later) but it is also a good example for the same reason because it points out where you can end up if you forgo efficiency alltogether and simply pile inefficient code upon inefficient code... ...usually i get to read either that exceptions are (or can be) free in terms of cpu cycles or that exceptions are "extremely expensive" (with numbers that show how expensive it is to throw and catch exceptions)... ...afaik the first assertion is nonsense...you only need to use your dissasembly window to, for example, inspect generated code for a function that has local objects with non trivial destructors and a call to function that can throw and compare that to the generated code for the same function but with a call to a function that cannot throw (and that is obvious to the compiler)... to see how much bookkeeping the compiler must do only because of the presence of exceptions/just the possibility that a throw might happen... the second remark, otoh, is irrelevant...nobody really cares how much it costs to throw an exception (if you are using them anyway), it should be an "exceptional" situation therefor happening rarely...the overhead of exceptions that concerns me comes from the overhead imposed by their very presence/possibility...(this can be tested by, for a test, building a big c++ library w/ and w/o exceptions, i've seen things like 4MB DLLs dropping to 3MB...) another example...i'm writting a small utility...that will open one file, one simple dialog and a few registry keys (or another os equivalent)...i want to be able to do this by handling errors using error codes...because if i'm forced to use exceptions then i must also link to the full crt which makes my util go from like 30kB to like 130kb... sure...i know that a lot of people will now say...so what...who cares about efficiency (atleast in this context or on this scale)...but "i answer that" with a reminder that we are talking about C++ here...which, afaik, "officially" inherited the ">you do not pay for what you do not use<" paradigm from C...and it seems to me that this "foundational imperative" is somehow lost today with "big name books" giving precedence to 'paranoid'/'defensive'/'safe'/'secure' and similar buzzwords (while labeling apriori efficiency concerns "the root of all evil")...thus giving c++ more and more a recognizable 'managed' smack...if you want ('forced upon you' type of) 'secure' and 'managed' go .net or java or ... there's plenty of 'managed' out there...but there is only one c++... perhaps i can make use of linus's well known irrational diatribe on c++... { http://thread.gmane.org/gmane.comp.version-control.git/57643/focus=57918 or http://lwn.net/Articles/249460 } ...to make my point. while it truly is a nonsensical diatribe it does, imho, make one good point (in the sense that, my, experience has showed this to be true at times): "Quite frankly, even if the choice of C were to do *nothing* but keep the C++ programmers out, that in itself would be a huge reason to use C." ...which is later explained with an example along the lines that c++ programmers are taught/encouraged/frequently seen to write code like std::string astring = "my" + std::string( "cool" ) + "string"; without ever thinking how many memory allocations this causes... ...this could also be reversed to say that we should use c++ if for nothing else than just to eliminate the typical bad/unsafe/unreadable/bug prone C-style code...but this would be to miss the point (which is not to argue with linus) but to say that maybe the c++ "imperative" to first and formost promote the writing of 'correct' code should be reformulated to (again) include efficiency...in the sense that the label 'correct' (code) also includes 'efficient' (code)... ...this is of course a slightly black-and-white way of looking at things and priorities have to be made "in the real world"...but to require that, atleast, the base line libraries (like the standard library and boost) do not make hardcoded/non configurable efficiency vs. "something else" compromises and tradeoffs is imho a justified whish/goal... anyways, if "we are now convinced" that neither of the "fundamentalist" approaches are (sufficiently) good we have to look at the third alternative/"school" and that is the hybrid approach... but how to go on about it..? ...the method proposed by boost::error_code, that you pass a reference to an error code object to a function based on which it decides whether to throw or store an error in the object has the: - advantage that it would work well with functions that otherwise return something else (like a valid result), i.e. it does not 'take up the space' of the return value - disadvantage that you have to predeclare an error_code variable if you do not want to use the default behaviour - disadvantage that you can forget to inspect your own error_code object (if you used it, as in the point above) - disadvantage that from the standpoint of the compiler the function will still have to be marked as possibly "throwable" so all the eh machinery would still have to be inserted into callers "no matter what" (unless it's a simple(r) function subject to inlining or transparent to the link time code generator) - advantage that the throw call is within the function (so the code is 'allocated' only once and the point of the throw is closer to the actual place and condition that caused the error) ...the method that would use throw and nothrow overloads has the: - advantage (in comparison to the above) that the compiler could recognize throw and no throw functions - disadvantage of a possible "maintenance nightmare" ...the method that would use "smart error objects" has the: - advantage of ensuring that errors are checked both if exceptions or error codes are used - advantage of a cleaner/less ugly interface (there is no error_code & parameter added to every function, and the need to do C-style predeclarations of error_code variables) - advantage that the library writer does not have to concern him/herself with the error reporting mechanism and the user has full/finer-grained control - disadvantage that it does not work well or at all with functions that would otherwise return something else (the iteartor-bool pair soultion with the std::map<>::insert() function comes to mind, but this seems way to complicated and ugly for return types not as trivial as an iterator) - disadvantage that callers might become a little "fatter" because of the "smarter"/"fatter" error code objects (but this, as previously mentioned, would vary significantly between use cases...i can even imagine cases where it would actually be beneficial...e.g. if many functions report the same type of error, then, even if exceptions are used mostly, this would/could result in smaller binaries because the code for throwing that error would exist in only one place, the error code class, instead of in every such function) - "debugger perspective" disadvantage (which, as argued before, i still do not actually consider a real issue) neither of the three methods solve the problem of functions that would throw/return different types of errors/exceptions... this specific issues could, perhaps, be used to make the descision as to which functions should use the hybrid error_code/exceptions (or just error codes) approach and when to switch to the 'standard' approach that uses exceptions...: when a function deals with only one domain (like io, parsing, regex, gui, resource management...) it maybe sensible that its error codes likewise be grouped into one domain...so that an io routine does not throw five different exception objects for five different error conditions that may arise in an io operation but use a single io_error/exception object that can be queried for an enum value that describes that actual/specific error... ...this way the problem of different exception types would be solved for single/specific domain functions... ...for functions that this soultion cannot be applied to, that can for example throw both an io, regex and a memory exception, we could simply say that these functions are high level api's for which the exception mechanism "naturally" fits (and could perhaps in certain complex situations even be more efficient than hordes of if then else statements) and just exceptions should be used... (sure things like variants could be used but this would probably be way to cumbersome if not plain ugly and unuseable...and would probably have no chance of becoming part of the standard) ...unfortunately this still leaves us with functions that are actually single-domain but can additionally fail due to dynamic memory allocation usage (throw bad_alloc)...which are probably frequent enough to constitute a separate problem... ...like the lexical_cast<> example (ok lexical_cast<>'s use of dynamic memory allocation and general inefficiency is imo so severe that it should be considered a bug and fixed but it still serves the purpose of the example)...we cannot say, ok let it still throw bad_alloc but report its domain-specific-error using error_codes because that would defeat the whole purpose of this proposal (for one thing, the compiler would still rightly consider the function as throwable)... ...the only thing that comes to mind currently is to consider "E_OUT_OF_MEMORY" a "part" of every domain... ...i can also envision mpl generated do_throw() functions that use steven watanabe's switch_ library to automatically convert error_codes to (differently typed) exceptions...(but this again probably has no chance of every becoming a part of the standard)... -- "That men do not learn very much from the lessons of history is the most important of all the lessons of history." Aldous Huxley

Domagoj Saric wrote:
hmm...this actually points out that i pretty much messed up in my first post/did not properly define neither the solution nor the problem it was trying to solve (actually mixed two solutions for two problems)...
[snip much too much text to read, let alone study]
...i can also envision mpl generated do_throw() functions that use steven watanabe's switch_ library to automatically convert error_codes to (differently typed) exceptions...(but this again probably has no chance of every becoming a part of the standard)...
I imagine there was useful information in your, but I won't be commenting on it as it stands, because I can't afford to take the time it would require. You might try sending a more succinct version of that post. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

"Stewart, Robert" <Robert.Stewart@sig.com> wrote in message news:DF2E67F3D097004694C8428C70A3FD69046F55F97B@msgbal516.ds.susq.com...
[snip much too much text to read, let alone study] ... I imagine there was useful information in your, but I won't be commenting on it as it stands, because I can't afford to take the time it would require. You might try sending a more succinct version of that post.
oh well :) perhaps i can give you a short introduction/"a bit extended toc"... firstly i tried to fix the ambiguity of my first post by separating the two problems of checked error codes and of the error-codes vs exceptions debate... then, after briefly summarizing and 'solving' the first problem i identified the "three schools of thought" in the error-codes vs exceptions debate... ...there i expanded on the arguments from the boost::error_code documentation in favour of the hybrid approach and against either of the "fundamentalist" approaches (only exceptions or only error codes)... then i summarized the three hybrid solutions so far proposed in this thread (error codes, overloads and "smart error objects") trying to document their so far percieved advantages and disadvantages... then i acknowledged that a hybrid approach is not universally applicable and tried to identify and define the line when a switch to exceptions must be made... ps. the probably largest part, in the middle of the post, is an "efficency rant" with real life examples of the effect that the presence of exceptions has on generated code as well as a 'case against' the 'managed' trends in c++...in general your garden variety "i do not want to pay for what i do not use" cry ;-D -- "That men do not learn very much from the lessons of history is the most important of all the lessons of history." Aldous Huxley

"Stewart, Robert" <Robert.Stewart@sig.com> wrote in message news:DF2E67F3D097004694C8428C70A3FD69046F26151F@msgbal516.ds.susq.com... Domagoj Saric wrote:
..._only_ if you save the returned object into a local scoped variable _and_ do not inspect it can the issues of "library after throw" and "abort on exception in destructor during unwind" come into play...
The complexity of this magical behavior
did you have anything other in mind (besides the issues below)?
From a debugging perspective, the exception will be thrown at the wrong point. ... the problem with throwing in the caller rather than at the point of error (i merged these two statements as they seem to state the same/similar point)
i'd say the 'debugging perspective' is here actually in the 'eye of the beholder' (i.e. up to the user to decide...in the sense that a function/library that uses the 'smart_error<>' approach has automatically given up the decision on what constitutes an exceptional situation/error/state and left that up to the user...and the interpretation of 'correctness' of that, again, depends on the perspective: if you value configurability more, it's a good thing, if you value 'paranoia' more, it's a bad thing...and so on...) ...the situation is the same as with existing os/crt/extern "c" functions that only return errors that you inspect and (sometimes) convert to exceptions...when such an exception is thrown at the error inspection site would you say that it was thrown at the wrong point (at the point of result code inspection instead of from within the function that returned the error)..? you still have the information which function call produced the error...if it is somehow critical that you know the exact source line at which the error was produced (within the function that you would rather to throw): - the debugger can be instructed to break at points of smart_error<> construction when the status_code with which it is constructed is different from some "error_success" value... - the function in question can save the __FILE__ and __LINE__ information into the returned smart_error<> object - the particular "smart_error<>" class can be "instructed" to assert or call _CrtDbgBreak when constructed with a non-success "actual_error" (when debugging)...
the overhead of checking to see whether to throw at each call site,
there are ways that this can be minimized (or in some cases eliminated): - move the exception object construction and the throw statement into a separate (preferably nontemplated) function marked as noninline - now we are left with an { if (!inspected && !succeded) do_throw() } which would/could probably translate to 5-6 cisc instructions - if the returned error object is imediately inspected after the function returns (as is the intended use) it is 'plain obvious' to the compiler that those "remaining instructions" are redundant and would be removed completely... - if, on the other hand, the returned error/status object is left uninspected, to throw if an error has occured, the only thing i see that could be done is somehow make it safe for the compiler to assume that the value of 'inspected' is always false right after exiting from the function (which should/must always be the case for correctly constructed error<> objects...right 'in' the return statement)...then we'd be left with a single if (!succeded) do_throw()...which is pretty much the same as in a usuall approach of converting an error code into an exception...and thus putting this case in a "grey"/"your mileage may vary" area...depends on particular use cases what would produce better code...
and the danger of throwing in the destructor during stack unwinding,
we seem to be "running in circles"...(afaik) there is no such danger for temporary objects...
makes overloading each affected function a pleasant alternative.
sorry i still don't see either of the presented options as a 'clear win alternative'... and what exactly do you mean under "affected function"? -- "That men do not learn very much from the lessons of history is the most important of all the lessons of history." Aldous Huxley

Domagoj Saric wrote:
"Stewart, Robert" <Robert.Stewart@sig.com> wrote in message news:DF2E67F3D097004694C8428C70A3FD69046F26151F@msgbal516.ds. susq.com... Domagoj Saric wrote:
..._only_ if you save the returned object into a local scoped variable _and_ do not inspect it can the issues of "library after throw" and "abort on exception in destructor during unwind" come into play...
The complexity of this magical behavior
did you have anything other in mind (besides the issues below)?
Not really. I was just noting that it seemed, to that point, a little hard to describe. Later when I tried, I found the description rather straightforward.
From a debugging perspective, the exception will be thrown at the wrong point. ... the problem with throwing in the caller rather than at the point of error
i'd say the 'debugging perspective' is here actually in the 'eye of the beholder' (i.e. up to the user to decide...in the sense that a function/library that uses the 'smart_error<>' approach has automatically given up the decision on what constitutes an exceptional situation/error/state and left that up to the user...and the
I think this is reasonable. The caller already decided to get a populated error_code rather than exceptions, so the source of the error isn't so important at that point. However, miscoded applications do get into production and it's awfully nice to get information about the real error -- not the, "Hey, stupid! You forgot to check for errors here" error -- to help diagnose the production problem.
- the debugger can be instructed to break at points of smart_error<> construction when the status_code with which it is constructed is different from some "error_success" value...
Yes, though of course conditional breakpoints are horribly slow in many debuggers.
- the function in question can save the __FILE__ and __LINE__ information into the returned smart_error<> object
Yes. That's part of what I was alluding to above.
- the particular "smart_error<>" class can be "instructed" to assert or call
I already mentioned asserting before throwing, so I agree with this.
_CrtDbgBreak when constructed with a non-success "actual_error" (when debugging)...
That's usually part of asserting on Windows as I recall.
the overhead of checking to see whether to throw at each call site,
there are ways that this can be minimized (or in some cases eliminated): - move the exception object construction and the throw statement into a separate (preferably nontemplated) function marked as noninline
The conditional logic is not affected by that, which I already assumed when I made the statement you quoted.
- now we are left with an { if (!inspected && !succeded) do_throw() } which would/could probably translate to 5-6 cisc instructions
That is more than zero instructions, even if your estimate is accurate. Besides, those instructions are conditionals which, if they are not guessed properly, will stall a highly pipelined CPU's instruction cache.
- if the returned error object is imediately inspected after the function returns (as is the intended use) it is 'plain obvious' to the compiler that those "remaining instructions" are redundant and would be removed completely...
What appears obvious to a human is not always so to an optimizer. You must prove that assertion by testing. [snip more optimization thoughts]
and the danger of throwing in the destructor during stack unwinding,
we seem to be "running in circles"...(afaik) there is no such danger for temporary objects...
Of course there is: error_code error; f(error); do_something_that_might_throw(); if (error) { deal_with_error(); } If do_something_that_might_throw() throws an exception, error will not have been checked for errors. ~error_code() might detect an uncaught exception and avoid rethrowing, but there are other scenarios that complicate that.
makes overloading each affected function a pleasant alternative.
sorry i still don't see either of the presented options as a 'clear win alternative'...
and what exactly do you mean under "affected function"?
Each function that might throw or use error_codes to report errors can use the proposed interface (Beman's original query) or can be overloaded. Given the complexity of what has been suggested for error_code to complain should its error state not be inspected and the variability of its making that complaint, means that simply overloading each such function is trivial by comparison. The semantics of overloading are well understood; nothing new need be invented. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

"Stewart, Robert" <Robert.Stewart@sig.com> wrote in message news:DF2E67F3D097004694C8428C70A3FD69046F55F92D@msgbal516.ds.susq.com...
However, miscoded applications do get into production and it's awfully nice to get information about the real error -- not the, "Hey, stupid! You forgot to check for errors here" error -- to help diagnose the production problem.
true...it was never my intention/part of my original idea to throw such "hey, stupid" errors as i explained and try to correct the ambigous wording of my first post in the "way too long" post ;)
- the debugger can be instructed to break at points of smart_error<> construction when the status_code with which it is constructed is different from some "error_success" value...
Yes, though of course conditional breakpoints are horribly slow in many debuggers.
true unfortunately...
_CrtDbgBreak when constructed with a non-success "actual_error" (when debugging)...
That's usually part of asserting on Windows as I recall.
yes, it was just an idea as it is perhaps easier to continue with execution after a plain _CrtDbgBreak() than after a "full" assert...
the overhead of checking to see whether to throw at each call site,
there are ways that this can be minimized (or in some cases eliminated): - move the exception object construction and the throw statement into a separate (preferably nontemplated) function marked as noninline
The conditional logic is not affected by that, which I already assumed when I made the statement you quoted.
the conditional logic itself is not, but the code as a whole is (it is smaller/less bloated...with all other consequences that entails...)
- now we are left with an { if (!inspected && !succeded) do_throw() } which would/could probably translate to 5-6 cisc instructions
That is more than zero instructions, even if your estimate is accurate. Besides, those instructions are conditionals which, if they are not guessed properly, will stall a highly pipelined CPU's instruction cache.
by all means...i never ment to claim it was 'practically zero' (you will usually rather see me complain about even a single instruction more...or even just a more complicated instruction...as in the [optional] layout thread...your "typical garden variety premature optimizer" :) ... ...i was mearly exploring the possible options and solutions...'thinking outloud'...if we cannot find a perfect/satisfying solution on the first try it does not mean that we should not try at all/that such a solution does not actually exist ;) and yes it seems all the hours spent with the disassembly window opened paid off :) ...the estimate was correct (if BOOLs, i.e. register sized integers, are used instead of bools, yes our "favourite" architecture thinks small bools are "evil") msvc++ 9 produces the following code: 00401C99 cmp dword ptr [esp],0 00401C9D jne $LN8 (401CABh) 00401C9F cmp dword ptr [esp+4],0 00401CA4 jne $LN8 (401CABh) 00401CA6 call do_throw (401C10h) this can now probably be further reduced to three instructions/a single test if the is_inspected bool is merged into a single free bit of the error_code (this would most probably hurt the immediately-inspected case as it would no longer be that transparent to the compiler but would benefit the use cases that use exceptions...things like this can anyhow be left as a matter of global and/or local configuration)...
- if the returned error object is imediately inspected after the function returns (as is the intended use) it is 'plain obvious' to the compiler that those "remaining instructions" are redundant and would be removed completely...
What appears obvious to a human is not always so to an optimizer. You must prove that assertion by testing.
i did of course...it's true (for msvc++ 9.0) ;)
[snip more optimization thoughts]
yes...well...the issue is obviously not trivial...i was trying to 'prove' that the issue (of more complex callers/call sites) is not immediate show stopper...because on one hand it can be minimized to a certain extent or completely removed in some cases while OTOH it is in fact not actually all that clear what/which solution is actually more complex/less efficient in real world usage scenarios... ...for example, in many situations removing throwing code from a function, using the smart error code approach, removes possibly order of magnitude more code from the function in question than it possibly adds to callling functions that need to have eh code anyway (if they let returned smart error code objects to auto convert to exceptions)...so in situations like these, unless there are many different call sites (that use the exception approach) for such a smart-error-code-returning function the actual outcome can turn out to be beneficial even for those scenarios... anyways, as said above, it seems to me that this particular issue is not an apriori show stopper and further time should be wasted on it only when (or if, as the discussion/further interest seems to be dead/dwindling) other issues and 'wrinkles' are polished...
and the danger of throwing in the destructor during stack unwinding,
we seem to be "running in circles"...(afaik) there is no such danger for temporary objects...
Of course there is:
error_code error; f(error); do_something_that_might_throw(); if (error) { deal_with_error(); }
umm...that was not my proposal (that looks sort of like a mixture of the boost::error_code approach and my proposal)...for one thing 'my smarter error codes' are not be default constructible or reusable but meant to be simply 'returned' (and also not converted to a local scoped object...this is an issues that still needs to be resolved)...
If do_something_that_might_throw() throws an exception, error will not have been checked for errors. ~error_code() might detect an uncaught exception and avoid rethrowing, but there are other scenarios that complicate that.
it seems to me that all so far mentioned scenarios regarding the issue of throwing in the destructor have been 'resolved' (including the gotw-047 issue)...
Each function that might throw or use error_codes to report errors can use the proposed interface (Beman's original query) or can be overloaded. Given the complexity of what has been suggested for error_code to complain should its error state not be inspected and the variability of its making that complaint, means that simply overloading each such function is trivial by comparison. The semantics of overloading are well understood; nothing new need be invented.
well virtual functions were also a "new invention" at one point yet it was still decided that a new standardized idiom was better than everyone reinventing the wheel all the time with manual function pointer mechanics... the same here...even if the "smart error code" approach is or seems "new" and/or complicated (i will leave it at that for this point, as the issue was already discussed elsewhere in the thread and in my 'too big' post) it does not necessarly mean that it is flawed or bad just because of it... ...instead of asking or hoping that your "favourite library" writer/maintainer will actually go through all the trouble of doubling his/hers public interface we can solve the problem only _once_ per library or actually/probably per language (if not per "universe")...by providing a standardized mean for library writers not to even worry about the error reporting/handling mechanism and at the same time for users to have full control over error handling...that is "safe"/"by the book" out of the box..yet, when and if one wants/needs it, configurable/"powerful" possibly less verbose and more efficient (and more small-utility-that-would-rather-not-link-to-the-full-crt friendly) than a default/"blind" "always use exceptions" approach... and "last but not least" sometimes the notion of "complexity" is also "in the eye of the beholder" (e.g. what some might regard as "complex" i might regard as "configurable" or "powerfull")... -- "That men do not learn very much from the lessons of history is the most important of all the lessons of history." Aldous Huxley

On Wed, Oct 28, 2009 at 6:46 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Emil Dotchevski" <emildotchevski@gmail.com> wrote in message news:c72e33ce0910281332m5ec6d444gf249609963661587@mail.gmail.com...
On Wed, Oct 28, 2009 at 12:40 PM, Detlef Vollmann <dv@vollmann.ch> wrote:
Domagoj Saric wrote:
~error() ( if ( !inspected ) throw actual_error_; )
This was discussed in the POSIX/C++ meeting 10 days ago, and was considered to be a good idea. Unfortunately, in the current C++ working paper, we have in 17.6.4.10 Restrictions on exception handling [res.on.exception.handling]: "4 Destructor operations defined in the C++ standard library shall not throw exceptions. "
A library should either throw when the error is detected or not. If it doesn't, the user might still throw, but the *library* throwing later seems a very bad idea. Not to mention the issue that throwing in a destructor can end up calling abort().
i mentioned the latter 'issue' already in the first post... generally both points seem to me like non-issues because they cannot become issues unintentionally... both can come into play _only_ if the user converts the temporary return object into a local scoped object/variable...which, as far as i know, you cannot do 'by accident'/unintentionally...you have to be verbose about it...(although, ironically the new auto makes it easier for you to do "the wrong thing"...but still not easy enough that you can do it by a 'non conscious mistake')...
bool diff(file srcA, file srcB, file output) { // get our files ready... error_code srcA_err = file_open(srcA); error_code srcB_err = file_open(srcB); error_code out_err = file_open(output); if (srcA_err || srcB_err || out_err) // check for errors return false; // do the diff... return true; } If srcA_err is true, then srcB_err and out_err aren't checked. On function exit, out_err throws on destruction, srcB_err throws on destruction during stack unwinding. (I think.) So that took a bit of thought for me to come up with, but the code doesn't look completely unreasonable, does it? Basically, you never want more than one actual error_code to exist at a time (per thread). Temporary copies would be OK (should be moveable anyhow, or ref counted). This could be checked for in the debug build. Tony <p.s. hope this doesn't get posted multiple times - gmail wasn't responding, so I'm resending...>

On 10/31/09 04:49, Gottlob Frege wrote:
bool diff(file srcA, file srcB, file output) { // get our files ready... error_code srcA_err = file_open(srcA); error_code srcB_err = file_open(srcB); error_code out_err = file_open(output);
if (srcA_err || srcB_err || out_err) // check for errors return false;
// do the diff...
return true; }
So that took a bit of thought for me to come up with, but the code doesn't look completely unreasonable, does it? Hmmm, that depends on your background. If you look at a respective POSIX program:
int srcA_err = open(srcA); int srcB_err = open(srcB); This will overwrite errno. So system level programmers are used to write: int err = open(srcA); check_error(err, "first source file"); err = open(srcB); check_error(err, "second source file"); So this specific issue should be teachable.
Basically, you never want more than one actual error_code to exist at a time (per thread). Hmmm, what about:
void do_the_diff(file &srcA, file &srcB, file &out) { error_code readA_err, readB_err, out_err; // chunksize, chunkA, chunkB bytes_read = read(&readA_err, srcA, &chunkA, chunksize); // check for and handle EINTR (only) bytes_read = read(&readB_err, srcB, &chunkB, chunksize); // check for and handle EINTR (only) // ... } Here we would throw in case any of the error_code object would have another error than EINTR. This becomes more interesting both contain such an error. I'm not so sure that I like this approach anymore... Detlef

"Gottlob Frege" <gottlobfrege@gmail.com> wrote in message news:97ffb310910302049u46d5cbddm557fb47bfbd663da@mail.gmail.com...
On Wed, Oct 28, 2009 at 6:46 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
i mentioned the latter 'issue' already in the first post... generally both points seem to me like non-issues because they cannot become issues unintentionally... both can come into play _only_ if the user converts the temporary return object into a local scoped object/variable...which, as far as i know, you cannot do 'by accident'/unintentionally...you have to be verbose about it...(although, ironically the new auto makes it easier for you to do "the wrong thing"...but still not easy enough that you can do it by a 'non conscious mistake')...
bool diff(file srcA, file srcB, file output) { // get our files ready... error_code srcA_err = file_open(srcA); error_code srcB_err = file_open(srcB); error_code out_err = file_open(output);
if (srcA_err || srcB_err || out_err) // check for errors return false;
// do the diff...
return true; }
If srcA_err is true, then srcB_err and out_err aren't checked. On function exit, out_err throws on destruction, srcB_err throws on destruction during stack unwinding. (I think.)
So that took a bit of thought for me to come up with, but the code doesn't look completely unreasonable, does it?
Basically, you never want more than one actual error_code to exist at a time (per thread). Temporary copies would be OK (should be moveable anyhow, or ref counted). This could be checked for in the debug build.
true...a good "find" ;) sure we could argue that this is "non-idiomatic" usage...but still, as you said, it is not "completely unreasonable" so it should also work correctly... there are two ways we could achieve this: ...one is to "smarten" the do_throw() function (i wrote about in other posts) to first do the "if( !std::uncaught_exception() )" check before doing the actual throw (this is, imho, safe and "non-evil" which i shall argue in a response to emil)... ...the other would require some sort of support from the compiler or some template/library trick to "forbid" (cause a compile error) creating a "smart_error_code<>" as anything other than a temporary and likewise forbid converting it to anything else but a temporary object...from a library POV perhaps this could be done so that returned objects are not actually "smart_error_code<>s" but some wrapper/different template instantiation "detail::temporary_smart_error_code<>" that the user does not have "legal" access to (its name, type and location are not defined by the standard) but, if one needs/wants to, can assign it (using move semantics) to a "proper" "smart_error_code<>"...and this assignment would turn off the "after throw" feature...the local scoped object would now only assert that it was inspected in its destructor...(and still provide a public do_throw() - like function so that the user can still choose to throw if he/she has no means to locally deal with the error)... -- "That men do not learn very much from the lessons of history is the most important of all the lessons of history." Aldous Huxley

On Sun, Nov 1, 2009 at 6:03 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Gottlob Frege" <gottlobfrege@gmail.com> wrote in message news:97ffb310910302049u46d5cbddm557fb47bfbd663da@mail.gmail.com...
On Wed, Oct 28, 2009 at 6:46 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
i mentioned the latter 'issue' already in the first post... generally both points seem to me like non-issues because they cannot become issues unintentionally... both can come into play _only_ if the user converts the temporary return object into a local scoped object/variable...which, as far as i know, you cannot do 'by accident'/unintentionally...you have to be verbose about it...(although, ironically the new auto makes it easier for you to do "the wrong thing"...but still not easy enough that you can do it by a 'non conscious mistake')...
bool diff(file srcA, file srcB, file output) { // get our files ready... error_code srcA_err = file_open(srcA); error_code srcB_err = file_open(srcB); error_code out_err = file_open(output);
if (srcA_err || srcB_err || out_err) // check for errors return false;
// do the diff...
return true; }
true...a good "find" ;) sure we could argue that this is "non-idiomatic" usage...but still, as you said, it is not "completely unreasonable" so it should also work correctly...
there are two ways we could achieve this: ...one is to "smarten" the do_throw() function (i wrote about in other posts) to first do the "if( !std::uncaught_exception() )" check before doing the actual throw (this is, imho, safe and "non-evil" which i shall argue in a response to emil)...
bool copy(file dest, file src) { error_code errSrc = open(src); error_code errDst = create(dest); if (errSrc || errDst) return false; //copy... return true; } In this case, we are not throwing during exception unwinding, but if errSrc is true, errDst is NOT checked, and thus throws. Should it? I think, at best, a smart_err_code should just assert() in debug only. ie check to make sure errors are being checked -> ie check for programmer error. As for throwing or not, lean towards throwing, supply both when there is good reason. I think throwing needs to become more common, particularly with multi-threading, because you can't necessarily check pre-conditions anymore - the preconditions might not last long enough for the function call. Even for file functions: if (!exists(file)) // check precondition create(file); // yet this throws "already exists" Tony

"Gottlob Frege" <gottlobfrege@gmail.com> wrote in message news:97ffb310911020958y7815771dpfc7686ebc03e4071@mail.gmail.com... On Sun, Nov 1, 2009 at 6:03 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
bool copy(file dest, file src) { error_code errSrc = open(src); error_code errDst = create(dest);
if (errSrc || errDst) return false;
//copy... return true; }
In this case, we are not throwing during exception unwinding, but if errSrc is true, errDst is NOT checked, and thus throws. Should it?
"oh darn" just when i thought a real world usage was found for std::uncaught_exception() (as an answer to gotw-047 question #3 :) ... ...well maybe it's still valid but it does not help us in this case... ...however the other proposed soultion (with "temporary error code" inaccessible to the user) would, as far as i can see, solve this problem also... ...if it were not for c++1x auto...which quite elegantly allows the user to unintentionally "shoot him/herself in the foot" in this particular case... ...as i'm not an expert on the upcoming standard (and the auto proposal) maybe someone smarter knows how (if anyhow possible) to circumvent this issue/disable auto declarations for certain types that you want to remain hidden from the user...?
I think, at best, a smart_err_code should just assert() in debug only. ie check to make sure errors are being checked -> ie check for programmer error.
as explained in a previous post, yes this is the basic usage/idea for a "smarter error code"... ...a separate problem is whether the "smarter error code" idea/design can be expanded/"smartened further" to provide a better/best possible solution for the error codes vs exceptions problem/dillema...
As for throwing or not, lean towards throwing, supply both when there is good reason.
the problem is that this only shifts the discussion onto the topic "what is good reason" (in this case)...;)
I think throwing needs to become more common, particularly with multi-threading, because you can't necessarily check pre-conditions anymore - the preconditions might not last long enough for the function call. Even for file functions:
if (!exists(file)) // check precondition create(file); // yet this throws "already exists"
this actually an old general multi-tasking (not just multithreading) issue...and exceptions do not help you there (what should throw in this case, exists(), create() or both?)...because its just wrong to do it that way... you call create() directly and then inspect the result as to see what actually happened (be it explicitly or implicitly, with error codes or exceptions)... -- "That men do not learn very much from the lessons of history is the most important of all the lessons of history." Aldous Huxley

"4 Destructor operations defined in the C++ standard library shall not throw exceptions. "
A library should either throw when the error is detected or not. If it doesn't, the user might still throw, but the *library* throwing later seems a very bad idea. Not to mention the issue that throwing in a destructor can end up calling abort().
Emil, Does that mean you are in favour of fixing https://svn.boost.org/trac/boost/ticket/2932 "iostreams file_descriptor: possible throw of exception in call to destructor"? This was raised seven months ago. Since there's been no response from the Boost.Iostreams maintainer, is it possible for someone else to make the trivial patch? Thanks, Gareth http://lists.boost.org/Archives/boost/2009/08/155157.php http://lists.boost.org/Archives/boost/2009/08/154611.php http://lists.boost.org/Archives/boost/2009/08/154844.php ************************************************************************ The information contained in this message or any of its attachments may be confidential and is intended for the exclusive use of the addressee(s). Any disclosure, reproduction, distribution or other dissemination or use of this communication is strictly prohibited without the express permission of the sender. The views expressed in this email are those of the individual and not necessarily those of Sony or Sony affiliated companies. Sony email is for business use only. This email and any response may be monitored by Sony to be in compliance with Sony's global policies and standards
participants (24)
-
Andrey Semashev
-
Andrey Tcherepanov
-
Beman Dawes
-
Christopher Kohlhoff
-
David Bergman
-
Detlef Vollmann
-
Domagoj Saric
-
Emil Dotchevski
-
Frank Mori Hess
-
Gottlob Frege
-
Jeffrey Bosboom
-
Marshall Clow
-
Michael Caisse
-
Michael Fawcett
-
Nevin Liber
-
Olaf van der Spek
-
OvermindDL1
-
Peter Dimov
-
Peter Foelsche
-
Scott McMurray
-
Steven Watanabe
-
Stewart, Robert
-
Sylvester-Bradley, Gareth
-
Thomas Klimpel