
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