[function] function wrapping and exception safety recap

Hi all, While it's fresh on my mind, I just want to recap the previous discussion and to make sure this is brought to Doug's attention. http://thread.gmane.org/gmane.comp.lib.boost.devel/209304 To summarize, there have been several complaints from users who don't use RTTI about boost::function's dependency on Boost.Exception. boost::function has a strong exception safety guarantee and uses boost::throw_exception to implement it. This affords users sophisticated options as to how exceptions are actually thrown (or not thrown in RTTI-free environments), since boost::throw_exception can be defined/customized by the user. This is a great feature for some, but others would prefer a function object wrapper that behaved more like a function pointer; i.e. no exception safety guarantee and no RTTI dependency. The following feature request and patch try to answer this demand by adding a new function object wrapper to the Boost.Function family of wrappers: boost::unsafe_function. boost::unsafe_function is simple to generate with only slight modification to the code that generates the existing boost::function/functionN family. https://svn.boost.org/trac/boost/ticket/4720 Some concerns have been raised regarding the efficiency of the NULL pointer check in boost::function's operator(), but I believe this is a side issue at best and possibly a case of premature optimization. In optimized object code, the overhead of the pointer check is so small that it is difficult to detect (from simple benchmarks with MSVC Release mode and gcc -02). Regardless, in circumstances where aggressive compiler optimization is unavailable, unsafe_function could be used to address this concern as well. (I measured a ~15% reduction in time with gcc -01, for example.) Of course, as Peter and Emil pointed out, one could eliminate the pointer check in boost::function if its default "empty" state actually wrapped a valid function, e.g. throw_bad_function_call(). This may be a good idea by itself, but again, this is tangential to the present feature request to provide a function object wrapper that is independent of boost::throw_exception and RTTI. Finally, there have been suggestions to alter boost::function's exception safety guarantee directly through either policies or constructor options. These solutions are functionally similar to unsafe_function, so preferences between them may be a matter of personal taste. Personally, I like having two distinct class templates for two orthogonal levels of exception safety. Also, I like that anytime I encounter an instance of boost::function, I know it has the same strong exception safety guarantee it has always had, without having to wonder how it was instantiated or constructed. So, in this case, my preference is to expand the Boost.Function family of function object wrappers, rather than alter boost::function itself. Daniel Walker

On Sat, Oct 9, 2010 at 12:38 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Finally, there have been suggestions to alter boost::function's exception safety guarantee directly through either policies or constructor options.
We used to have an Allocator parameter to the boost::function template and it was removed (just in time for this change to also be reflected in C++0x) to reduce coupling. Adding any policies to boost::function would undo all of the benefits of that change. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On 11 October 2010 00:01, Emil Dotchevski <emil@revergestudios.com> wrote:
On Sat, Oct 9, 2010 at 12:38 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Finally, there have been suggestions to alter boost::function's exception safety guarantee directly through either policies or constructor options.
We used to have an Allocator parameter to the boost::function template and it was removed (just in time for this change to also be reflected in C++0x) to reduce coupling.
So what exactly is the proposed behavior if the function object cannot fit in the small object optimization space of unsafe_function and the allocation fails? -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404

On Mon, Oct 11, 2010 at 2:49 AM, Nevin Liber <nevin@eviloverlord.com> wrote:
On 11 October 2010 00:01, Emil Dotchevski <emil@revergestudios.com> wrote:
On Sat, Oct 9, 2010 at 12:38 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Finally, there have been suggestions to alter boost::function's exception safety guarantee directly through either policies or constructor options.
We used to have an Allocator parameter to the boost::function template and it was removed (just in time for this change to also be reflected in C++0x) to reduce coupling.
So what exactly is the proposed behavior if the function object cannot fit in the small object optimization space of unsafe_function and the allocation fails?
As proposed, unsafe_function has the same semantics as boost::function with one (and only one) exception: the behavior of operator() is undefined when it has no target. (The patch includes documentation for this, though it may be difficult to read unless you generate the HTML.) So, with respect to small object allocation, it behaves the same as boost::function. After a failed allocation, the wrapper has no target and future calls to operator bool() and empty() will return false. Daniel Walker

On Mon, Oct 11, 2010 at 10:45 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 2:49 AM, Nevin Liber <nevin@eviloverlord.com> wrote:
On 11 October 2010 00:01, Emil Dotchevski <emil@revergestudios.com> wrote:
On Sat, Oct 9, 2010 at 12:38 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Finally, there have been suggestions to alter boost::function's exception safety guarantee directly through either policies or constructor options.
We used to have an Allocator parameter to the boost::function template and it was removed (just in time for this change to also be reflected in C++0x) to reduce coupling.
So what exactly is the proposed behavior if the function object cannot fit in the small object optimization space of unsafe_function and the allocation fails?
As proposed, unsafe_function has the same semantics as boost::function with one (and only one) exception: the behavior of operator() is undefined when it has no target.
If that was the only motivation, you could just disable exception handling, and then define: namespace boost { void throw_exception( std::exception const & ) { assert(0); } } Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Mon, Oct 11, 2010 at 2:05 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Mon, Oct 11, 2010 at 10:45 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 2:49 AM, Nevin Liber <nevin@eviloverlord.com> wrote:
On 11 October 2010 00:01, Emil Dotchevski <emil@revergestudios.com> wrote:
On Sat, Oct 9, 2010 at 12:38 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Finally, there have been suggestions to alter boost::function's exception safety guarantee directly through either policies or constructor options.
We used to have an Allocator parameter to the boost::function template and it was removed (just in time for this change to also be reflected in C++0x) to reduce coupling.
So what exactly is the proposed behavior if the function object cannot fit in the small object optimization space of unsafe_function and the allocation fails?
As proposed, unsafe_function has the same semantics as boost::function with one (and only one) exception: the behavior of operator() is undefined when it has no target.
If that was the only motivation, you could just disable exception handling, and then define:
namespace boost { void throw_exception( std::exception const & ) { assert(0); } }
Correct. But users have complained about this, which is exactly the motivation for unsafe_function. It works out-of-the-box in RTTI-free environments with no dependency on boost::throw_exception. It's a simple problem really. Daniel Walker

On Mon, Oct 11, 2010 at 2:45 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 2:05 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Mon, Oct 11, 2010 at 10:45 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 2:49 AM, Nevin Liber <nevin@eviloverlord.com> wrote:
On 11 October 2010 00:01, Emil Dotchevski <emil@revergestudios.com> wrote:
On Sat, Oct 9, 2010 at 12:38 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Finally, there have been suggestions to alter boost::function's exception safety guarantee directly through either policies or constructor options.
We used to have an Allocator parameter to the boost::function template and it was removed (just in time for this change to also be reflected in C++0x) to reduce coupling.
So what exactly is the proposed behavior if the function object cannot fit in the small object optimization space of unsafe_function and the allocation fails?
As proposed, unsafe_function has the same semantics as boost::function with one (and only one) exception: the behavior of operator() is undefined when it has no target.
If that was the only motivation, you could just disable exception handling, and then define:
namespace boost { void throw_exception( std::exception const & ) { assert(0); } }
Correct. But users have complained about this, which is exactly the motivation for unsafe_function. It works out-of-the-box in RTTI-free environments with no dependency on boost::throw_exception. It's a simple problem really.
P.S. Sorry I spoke to soon. That's not exactly correct. A user could do what you describe, but boost::function could not, since that would change its exception safety guarantee; i.e. it would no longer throw (or call a user definable function) when it had no target. This is the other motivation for unsafe_function: the simplest way to work out-of-the-box in RTTI-free environments is to remove the exception safety guarantee, which these users do not want to begin with. Daniel Walker

On Mon, Oct 11, 2010 at 11:53 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 2:45 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 2:05 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Mon, Oct 11, 2010 at 10:45 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 2:49 AM, Nevin Liber <nevin@eviloverlord.com> wrote:
On 11 October 2010 00:01, Emil Dotchevski <emil@revergestudios.com> wrote:
On Sat, Oct 9, 2010 at 12:38 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote: > Finally, there have been suggestions to alter boost::function's > exception safety guarantee directly through either policies or > constructor options.
We used to have an Allocator parameter to the boost::function template and it was removed (just in time for this change to also be reflected in C++0x) to reduce coupling.
So what exactly is the proposed behavior if the function object cannot fit in the small object optimization space of unsafe_function and the allocation fails?
As proposed, unsafe_function has the same semantics as boost::function with one (and only one) exception: the behavior of operator() is undefined when it has no target.
If that was the only motivation, you could just disable exception handling, and then define:
namespace boost { void throw_exception( std::exception const & ) { assert(0); } }
Correct. But users have complained about this, which is exactly the motivation for unsafe_function. It works out-of-the-box in RTTI-free environments with no dependency on boost::throw_exception. It's a simple problem really.
P.S. Sorry I spoke to soon. That's not exactly correct. A user could do what you describe, but boost::function could not, since that would change its exception safety guarantee; i.e. it would no longer throw (or call a user definable function) when it had no target.
This is not exception safety issue, it is a choice between defined and undefined behavior. Undefined behavior is desirable when there are performance or portability problems with defining a behavior. No such problems exist with the current boost::function semantics. You can't both want undefined behavior and be against any particular behavior, such as throwing an exception or calling a function. The only viewpoint from which this discussion makes sense to me is that it might be beneficial to remove the coupling between boost/function.hpp and boost/throw_exception.hpp, although as suggested by Nevin this still doesn't address the question of what happens if a constructor fails to establish the boost::function invariant. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Mon, Oct 11, 2010 at 3:20 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Mon, Oct 11, 2010 at 11:53 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 2:45 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 2:05 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Mon, Oct 11, 2010 at 10:45 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 2:49 AM, Nevin Liber <nevin@eviloverlord.com> wrote:
On 11 October 2010 00:01, Emil Dotchevski <emil@revergestudios.com> wrote: > On Sat, Oct 9, 2010 at 12:38 PM, Daniel Walker > <daniel.j.walker@gmail.com> wrote: >> Finally, there have been suggestions to alter boost::function's >> exception safety guarantee directly through either policies or >> constructor options. > > We used to have an Allocator parameter to the boost::function template > and it was removed (just in time for this change to also be reflected > in C++0x) to reduce coupling.
So what exactly is the proposed behavior if the function object cannot fit in the small object optimization space of unsafe_function and the allocation fails?
As proposed, unsafe_function has the same semantics as boost::function with one (and only one) exception: the behavior of operator() is undefined when it has no target.
If that was the only motivation, you could just disable exception handling, and then define:
namespace boost { void throw_exception( std::exception const & ) { assert(0); } }
Correct. But users have complained about this, which is exactly the motivation for unsafe_function. It works out-of-the-box in RTTI-free environments with no dependency on boost::throw_exception. It's a simple problem really.
P.S. Sorry I spoke to soon. That's not exactly correct. A user could do what you describe, but boost::function could not, since that would change its exception safety guarantee; i.e. it would no longer throw (or call a user definable function) when it had no target.
This is not exception safety issue, it is a choice between defined and undefined behavior.
A strong exception safety guarantee is a defined behavior. unsafe_function removes that guarantee and leaves its behavior undefined when its preconditions aren't met; namely, it dereferences a null pointer, which has an undefined (and undefinable) behavior.
Undefined behavior is desirable when there are performance or portability problems with defining a behavior. No such problems exist with the current boost::function semantics. You can't both want undefined behavior and be against any particular behavior, such as throwing an exception or calling a function.
boost::function's behavior is defined in all circumstance, even when it's preconditions are met. That's a necessary requirement of a strong exception safety guarantee. However, some users have complained about the definitions. From listening, I believe they would prefer a function wrapper that behaved more like a function pointer when its preconditions are not met; i.e. they do not want RTTI or boost::throw_exception. The simplest way to establish this is to adopt no exception safety guarantee. (I am trying to follow Dave's exception safety paper by the way. I linked to it in the documentation in the patch, to provide users some background.)
The only viewpoint from which this discussion makes sense to me is that it might be beneficial to remove the coupling between boost/function.hpp and boost/throw_exception.hpp, <snip>
Yes, that's exactly the way you should look at it. However, the coupling is a good thing for boost::function. If you're going to offer a strong exception safety guarantee, Boost.Exception is a good way to implement it. So, for one group of users, boost::function is perfect as is. But one size does not fit all. Another group of users, would like a function wrapper without coupling Boost.Exception, and indeed, without an exception safety guarantee. unsafe_function address the demands of this second group of users. Daniel Walker

On Mon, Oct 11, 2010 at 12:57 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 3:20 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Mon, Oct 11, 2010 at 11:53 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 2:45 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 2:05 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Mon, Oct 11, 2010 at 10:45 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 2:49 AM, Nevin Liber <nevin@eviloverlord.com> wrote: > On 11 October 2010 00:01, Emil Dotchevski <emil@revergestudios.com> wrote: >> On Sat, Oct 9, 2010 at 12:38 PM, Daniel Walker >> <daniel.j.walker@gmail.com> wrote: >>> Finally, there have been suggestions to alter boost::function's >>> exception safety guarantee directly through either policies or >>> constructor options. >> >> We used to have an Allocator parameter to the boost::function template >> and it was removed (just in time for this change to also be reflected >> in C++0x) to reduce coupling. > > So what exactly is the proposed behavior if the function object cannot > fit in the small object optimization space of unsafe_function and the > allocation fails?
As proposed, unsafe_function has the same semantics as boost::function with one (and only one) exception: the behavior of operator() is undefined when it has no target.
If that was the only motivation, you could just disable exception handling, and then define:
namespace boost { void throw_exception( std::exception const & ) { assert(0); } }
Correct. But users have complained about this, which is exactly the motivation for unsafe_function. It works out-of-the-box in RTTI-free environments with no dependency on boost::throw_exception. It's a simple problem really.
P.S. Sorry I spoke to soon. That's not exactly correct. A user could do what you describe, but boost::function could not, since that would change its exception safety guarantee; i.e. it would no longer throw (or call a user definable function) when it had no target.
This is not exception safety issue, it is a choice between defined and undefined behavior.
A strong exception safety guarantee is a defined behavior.
Any behavior fits "undefined behavior". Like I said, if someone wants undefined behavior, they can't be against any particular behavior, including throwing an exception.
Another group of users, would like a function wrapper without coupling Boost.Exception, and indeed, without an exception safety guarantee. unsafe_function address the demands of this second group of users.
What is the problem with adding a constructor such that you could say: boost::function<T>(f,std::nothrow) This way, I'm pretty sure that as long a program only instantiates the nothrow constructors, the resulting executable won't depend on boost::throw_exception. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Mon, Oct 11, 2010 at 2:13 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Mon, Oct 11, 2010 at 12:57 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 3:20 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Mon, Oct 11, 2010 at 11:53 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 2:45 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 2:05 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Mon, Oct 11, 2010 at 10:45 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote: > On Mon, Oct 11, 2010 at 2:49 AM, Nevin Liber <nevin@eviloverlord.com> wrote: >> On 11 October 2010 00:01, Emil Dotchevski <emil@revergestudios.com> wrote: >>> On Sat, Oct 9, 2010 at 12:38 PM, Daniel Walker >>> <daniel.j.walker@gmail.com> wrote: >>>> Finally, there have been suggestions to alter boost::function's >>>> exception safety guarantee directly through either policies or >>>> constructor options. >>> >>> We used to have an Allocator parameter to the boost::function template >>> and it was removed (just in time for this change to also be reflected >>> in C++0x) to reduce coupling. >> >> So what exactly is the proposed behavior if the function object cannot >> fit in the small object optimization space of unsafe_function and the >> allocation fails? > > As proposed, unsafe_function has the same semantics as boost::function > with one (and only one) exception: the behavior of operator() is > undefined when it has no target.
If that was the only motivation, you could just disable exception handling, and then define:
namespace boost { void throw_exception( std::exception const & ) { assert(0); } }
Correct. But users have complained about this, which is exactly the motivation for unsafe_function. It works out-of-the-box in RTTI-free environments with no dependency on boost::throw_exception. It's a simple problem really.
P.S. Sorry I spoke to soon. That's not exactly correct. A user could do what you describe, but boost::function could not, since that would change its exception safety guarantee; i.e. it would no longer throw (or call a user definable function) when it had no target.
This is not exception safety issue, it is a choice between defined and undefined behavior.
A strong exception safety guarantee is a defined behavior.
Any behavior fits "undefined behavior". Like I said, if someone wants undefined behavior, they can't be against any particular behavior, including throwing an exception.
Another group of users, would like a function wrapper without coupling Boost.Exception, and indeed, without an exception safety guarantee. unsafe_function address the demands of this second group of users.
What is the problem with adding a constructor such that you could say:
boost::function<T>(f,std::nothrow)
This way, I'm pretty sure that as long a program only instantiates the nothrow constructors, the resulting executable won't depend on boost::throw_exception.
If that is a template parameter that would work, but if not that adds overhead. Personally, I still do not see what is wrong with having a default function, so if boost::function is default constructed or ever set to null then it is set to this default function instead (which by default might throw? But could be overridden on a per object bases, such as when you just want it to do nothing if it is not set or so, I see plenty of use cases and it satisfies all that is wanted and it removes the if(function_pointer == null) check.

On Mon, Oct 11, 2010 at 4:13 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Mon, Oct 11, 2010 at 12:57 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 3:20 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Mon, Oct 11, 2010 at 11:53 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 2:45 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, Oct 11, 2010 at 2:05 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Mon, Oct 11, 2010 at 10:45 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote: > On Mon, Oct 11, 2010 at 2:49 AM, Nevin Liber <nevin@eviloverlord.com> wrote: >> On 11 October 2010 00:01, Emil Dotchevski <emil@revergestudios.com> wrote: >>> On Sat, Oct 9, 2010 at 12:38 PM, Daniel Walker >>> <daniel.j.walker@gmail.com> wrote: >>>> Finally, there have been suggestions to alter boost::function's >>>> exception safety guarantee directly through either policies or >>>> constructor options. >>> >>> We used to have an Allocator parameter to the boost::function template >>> and it was removed (just in time for this change to also be reflected >>> in C++0x) to reduce coupling. >> >> So what exactly is the proposed behavior if the function object cannot >> fit in the small object optimization space of unsafe_function and the >> allocation fails? > > As proposed, unsafe_function has the same semantics as boost::function > with one (and only one) exception: the behavior of operator() is > undefined when it has no target.
If that was the only motivation, you could just disable exception handling, and then define:
namespace boost { void throw_exception( std::exception const & ) { assert(0); } }
Correct. But users have complained about this, which is exactly the motivation for unsafe_function. It works out-of-the-box in RTTI-free environments with no dependency on boost::throw_exception. It's a simple problem really.
P.S. Sorry I spoke to soon. That's not exactly correct. A user could do what you describe, but boost::function could not, since that would change its exception safety guarantee; i.e. it would no longer throw (or call a user definable function) when it had no target.
This is not exception safety issue, it is a choice between defined and undefined behavior.
A strong exception safety guarantee is a defined behavior.
Any behavior fits "undefined behavior". Like I said, if someone wants undefined behavior, they can't be against any particular behavior, including throwing an exception.
Another group of users, would like a function wrapper without coupling Boost.Exception, and indeed, without an exception safety guarantee. unsafe_function address the demands of this second group of users.
What is the problem with adding a constructor such that you could say:
boost::function<T>(f,std::nothrow)
This way, I'm pretty sure that as long a program only instantiates the nothrow constructors, the resulting executable won't depend on boost::throw_exception.
True, that can be done, but boost::function is still default constructible and can still be cleared through assigning 0. So, you end up back to the exception safety question of how operator() behaves when the wrapper is empty. As you suggest, you could have the behavior depend on how it was constructed, so sometimes boost::function has a strong exception guarantee, sometimes it has a nothrow guarantee (and presumably, it's a no-op when empty). This is a matter of personal preference. To me it's simpler to say that boost::function always has a strong exception safety guarantee, as is currently the case, and other function object wrappers could be added to offer other guarantees, including no guarantee, like a plain vanilla function pointer, which is what unsafe_function does. Under this scheme, we could also add nothrow_function that would offer a nothrow guarantee, and semantically, it would be a no-op when empty, per your example. Daniel Walker

On Tue, Oct 12, 2010 at 11:08 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
True, that can be done, but boost::function is still default constructible and can still be cleared through assigning 0. So, you end up back to the exception safety question of how operator() behaves when the wrapper is empty. As you suggest, you could have the behavior depend on how it was constructed, so sometimes boost::function has a strong exception guarantee, sometimes it has a nothrow guarantee (and presumably, it's a no-op when empty).
Here is some code to make sure we're talking about the same thing: #include <new> using namespace std; extern void throw_exception(); template <class T> class function { public: void (*f)(); function():f(&throw_exception) { } function( nothrow_t ): f(0) { } void operator()() { f(); } }; int main() { function<int()> f(); //by default, you get link error. //function<int()> f(nothrow); //crash, but no link error. f(); } It would have been nicer if op() didn't throw to begin with but because that's how it has been, this should remain the default behavior. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On 12 October 2010 13:28, Emil Dotchevski <emil@revergestudios.com> wrote:
It would have been nicer if op() didn't throw to begin with but because that's how it has been, this should remain the default behavior.
More than that, it is the behavior that is going into C++0x. -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404

"Nevin Liber" <nevin@eviloverlord.com> wrote in message news:AANLkTinQDNaoUawizRYeimNPRq0Ob9cFiAumEub_tLvd@mail.gmail.com...
On 12 October 2010 13:28, Emil Dotchevski <emil@revergestudios.com> wrote:
It would have been nicer if op() didn't throw to begin with but because that's how it has been, this should remain the default behavior.
More than that, it is the behavior that is going into C++0x.
Why? To both of those arguments, why? Should we have stuck with all the tried and tested C-style 'beauty' that we now consider ugly and obsolete just because 'that's how it was done 'back in the day'? While C++ is a great language, its standard library is not (a fact nicely demonstrated at http://www.ultimatepp.org/www$uppweb$vsstd$en-us.html http://www.ultimatepp.org/www$uppweb$vsd$en-us.html) so why should we worship it like it is? As if the epic failure of the standard library called iostreams somehow just created a precedent that says that its ok to put inefficient-by-design code into the standard library, and if you manage to get it in it will stay there forever... If we already know that boost::function has (relatively) inefficient invocation and copying, is not configurable and can cause unnecessary bloat why not fix it now even if that makes it no longer a 'perfect copy' of std::function...? After all: - people come/came to use Boost exactly because the standard library did not satisfy them - (for example) boost::mem_fn is not a 'perfect copy' of std::mem_fn - the 'proper' boost::function can always be renamed to something else (boost::functional/functionoid or something) and boost::function can be a wrapper around the 'proper' implementation that mimics std::function... -- "What Huxley teaches is that in the age of advanced technology, spiritual devastation is more likely to come from an enemy with a smiling face than from one whose countenance exudes suspicion and hate." Neil Postman

"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTin=9rdwNqHQZRAPj9=9YngdTD0mX7zQ8S1LmhQm@mail.gmail.com...
On Sat, Oct 9, 2010 at 12:38 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Finally, there have been suggestions to alter boost::function's exception safety guarantee directly through either policies or constructor options.
We used to have an Allocator parameter to the boost::function template and it was removed (just in time for this change to also be reflected in C++0x) to reduce coupling. Adding any policies to boost::function would undo all of the benefits of that change.
What (de)coupling (and the related benefits) are you referring to? The ABI compatibility/stability and safe cross .DLL/.so passing arguments also used for the justification of the hardcoded dynamic deleter in shared_ptr or something else? -- "What Huxley teaches is that in the age of advanced technology, spiritual devastation is more likely to come from an enemy with a smiling face than from one whose countenance exudes suspicion and hate." Neil Postman

On Mon, Oct 11, 2010 at 7:49 AM, Domagoj Saric <domagoj.saric@littleendian.com> wrote:
"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTin=9rdwNqHQZRAPj9=9YngdTD0mX7zQ8S1LmhQm@mail.gmail.com...
On Sat, Oct 9, 2010 at 12:38 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Finally, there have been suggestions to alter boost::function's exception safety guarantee directly through either policies or constructor options.
We used to have an Allocator parameter to the boost::function template and it was removed (just in time for this change to also be reflected in C++0x) to reduce coupling. Adding any policies to boost::function would undo all of the benefits of that change.
What (de)coupling (and the related benefits) are you referring to? The ABI compatibility/stability and safe cross .DLL/.so passing arguments also used for the justification of the hardcoded dynamic deleter in shared_ptr or something else?
Yes, that ability is a result of the reduced coupling. One of the main objectives of boost::function is type erasure: being able to hold on to functions without knowing their exact type, and the allocator policy directly interfered with that. Also, with the removal of the default Allocator parameter of the main boost::function template, it is possible to define APIs in terms of boost::function without including boost/function.hpp; just a declaration in the API header suffices: namespace boost { template <class> function; } void foo( boost::function<void()> const & ); Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTimenndg89tGkUepkP-5mizv_NtNEdh-DAkNG1Tv@mail.gmail.com... On Mon, Oct 11, 2010 at 7:49 AM, Domagoj Saric <domagoj.saric@littleendian.com> wrote:
What (de)coupling (and the related benefits) are you referring to? The ABI compatibility/stability and safe cross .DLL/.so passing arguments also used for the justification of the hardcoded dynamic deleter in shared_ptr or something else?
Yes, that ability is a result of the reduced coupling. One of the main objectives of boost::function is type erasure: being able to hold on to functions without knowing their exact type, and the allocator policy directly interfered with that.
Just like in the case of shared_ptr, I still don't buy this argument...: why would replacing hardcoded dynamic behaviour with configurability through policies 'interfere' with type erasure? Adding more template parameters in no way changes the first/main parameter or causes the actual type stored in the boost::function to somehow 'leak' out through the interface... As for the 'safe shared module border crossing' argument you are still left with the _option_ of using a dynamic policy for anything that might use the runtime library...The fact that an inexperienced user might forget to do so (while at the same time linking with different runtimes in different 'DLLs') thus shooting oneself in the foot is no justification for crippling other users that 'know what they are doing'...AFAIK C++ is _not_ a managed language where the case of Joe Sixpack is the lead use case...
Also, with the removal of the default Allocator parameter of the main boost::function template, it is possible to define APIs in terms of boost::function without including boost/function.hpp; just a declaration in the API header suffices:
namespace boost { template <class> function; }
void foo( boost::function<void()> const & );
I'm sorry if I am ignorant of some crucial C++ fact but I fail to see why the same thing could not be done if boost::function had more template parameters? Furthermore, whatever the case my be, this forward declaration ability would make any relevance only in headers that mention boost::function only as function parameters and return types and/or as members held by reference _and_ one is using an ancient compiler incapable of including/parsing Boost.Function headers in the blink of an eye....hopefully this not the use case for modelling (and crippling) a Boost library interface... -- "What Huxley teaches is that in the age of advanced technology, spiritual devastation is more likely to come from an enemy with a smiling face than from one whose countenance exudes suspicion and hate." Neil Postman

On Tue, Oct 19, 2010 at 12:34 AM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTimenndg89tGkUepkP-5mizv_NtNEdh-DAkNG1Tv@mail.gmail.com...
On Mon, Oct 11, 2010 at 7:49 AM, Domagoj Saric <domagoj.saric@littleendian.com> wrote:
What (de)coupling (and the related benefits) are you referring to? The ABI compatibility/stability and safe cross .DLL/.so passing arguments also used for the justification of the hardcoded dynamic deleter in shared_ptr or something else?
Yes, that ability is a result of the reduced coupling. One of the main objectives of boost::function is type erasure: being able to hold on to functions without knowing their exact type, and the allocator policy directly interfered with that.
Just like in the case of shared_ptr, I still don't buy this argument...: why would replacing hardcoded dynamic behaviour with configurability through policies 'interfere' with type erasure?
Because function<T,A1> is not the same type as function<T,A2>. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTikGfE0KcMXjPMpqL-+12rUbouOrVGr1Rfgr_m_-@mail.gmail.com...
On Tue, Oct 19, 2010 at 12:34 AM, Domagoj Saric <dsaritz@gmail.com> wrote:
Just like in the case of shared_ptr, I still don't buy this argument...: why would replacing hardcoded dynamic behaviour with configurability through policies 'interfere' with type erasure?
Because function<T,A1> is not the same type as function<T,A2>.
And? So is function<T1> not the same type as function<T2>...what difference does that make? The point is, AFAIK, to erase the type of the object you put into a boost::function<> instance, not the type of boost::function itself...after all unlike in Objective-C(++) in C++ everything has _some_ type in the end... If one wants to fix(ate) one or all template parameters of boost::function in an interface (for example to what they are now implicitly hardcoded when you have no option to choose) one is perfectly free to do so (thus e.g. transforming your function<T, A1> to function<T>)... ...the difference is that the user has the >_option_< (or is time to be pathetic and say "freedom") to choose... You can always go from "freedom" to "rule of thumb"/"happy Joe Sixpack" but not vice verse... -- "What Huxley teaches is that in the age of advanced technology, spiritual devastation is more likely to come from an enemy with a smiling face than from one whose countenance exudes suspicion and hate." Neil Postman

On Tue, Oct 19, 2010 at 1:45 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTikGfE0KcMXjPMpqL-+12rUbouOrVGr1Rfgr_m_-@mail.gmail.com...
On Tue, Oct 19, 2010 at 12:34 AM, Domagoj Saric <dsaritz@gmail.com> wrote:
Just like in the case of shared_ptr, I still don't buy this argument...: why would replacing hardcoded dynamic behaviour with configurability through policies 'interfere' with type erasure?
Because function<T,A1> is not the same type as function<T,A2>.
And? So is function<T1> not the same type as function<T2>...what difference does that make?
The difference is that the current boost::function interface does not burden the user with having to remember the type of the allocator for each individual function object. You could for example organize a bunch of function<void()> objects in an array, even if each one of them uses a different type of allocator. What is the advantage of the function<T,A> interface anyway?
The point is, AFAIK, to erase the type of the object you put into a boost::function<> instance, not the type of boost::function itself...after all unlike in Objective-C(++) in C++ everything has _some_ type in the end...
Everything has a type, but the user doesn't have to know the type of everything. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTim6iz7OBR-jT0e5ffFFXguFjNUDiK77LWGO+Ff9@mail.gmail.com...
On Tue, Oct 19, 2010 at 1:45 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTikGfE0KcMXjPMpqL-+12rUbouOrVGr1Rfgr_m_-@mail.gmail.com...
On Tue, Oct 19, 2010 at 12:34 AM, Domagoj Saric <dsaritz@gmail.com> wrote:
Just like in the case of shared_ptr, I still don't buy this argument...: why would replacing hardcoded dynamic behaviour with configurability through policies 'interfere' with type erasure?
Because function<T,A1> is not the same type as function<T,A2>.
And? So is function<T1> not the same type as function<T2>...what difference does that make?
The difference is that the current boost::function interface does not burden the user with having to remember the type of the allocator for each individual function object. You could for example organize a bunch of function<void()> objects in an array, even if each one of them uses a different type of allocator.
- 'Burden of remembering'? - that's what default template parameters and typedefs are for...for example my changed boost::function<> has two template parameters yet it still functions as a drop-in replacement for the original one because the second parameter is defaulted to give it the same semantics as the original one...So, once again, giving options does not necessarily take away simplicity while hardcoding 'simplicity' _does_ take away options... - 'Dynamicness'/'polymorphism', as explained so many times before...you can have this also even if you allow an arbitrary amount of policies through an arbitrary amount of template parameters because this gives you the >option< of specifying dynamic/polymorphic policies at compile time and then using different implementations of the same policies at runtime....OTOH hardcoding dynamic policies does _not_ give you the option to benefit from compile-time driven efficiency... "So, once again, giving options does not necessarily take away simplicity while hardcoding 'simplicity' _does_ take away options..." - 'Burden the user'? Are we again designing around "Managed Joe Sixpack"? Last time I checked, in C++ (the language, unfortunately not necessarily the standard library) having more options was called 'power' not 'burden'...Why can't you accept that your preconceptions of what is 'good enough for everyone' just simply is not good enough for everyone, as proven time and time again by these very questions and requests on this very list? AFAIK C++ used to boast by being able to do both high level and low level things...if you start hardcoding 'rule of thumb' decisions into the core of the standard library that 'power'/'magic'/'burden?' is quickly lost...and we're in 'managed land' again...where the sun always shines...until of course you try to think outside the box/'the standard library'... - Why did you use allocators as an argument here anyway? This looks like a straw man, AFAICT noone contested this yet...In any case, even this argument does not help your 'case'/POV (which is defending the status quo, if I deduced correctly), quite the opposite if I may say. Namely, the issue of allocators is different (from for example on-empty policy) because boost::function<> needs the desired allocator only on construction and assignment so explicitly/manually/separately passing them as arguments then (at runtime, instead of specifying them once through a template parameter) incurs no overhead and can even be seen as giving more power (or in your view, burdening the user) as you can use different allocators at different times...thus, seeing it this way, it becomes quite dubious to claim that this runtime way of specifying allocators actually makes things easier for users when in reality it seems the opposite, because instead of specifying your desired allocator only once you have to specify/pass it every time...QeD. ps. are you implying that the various allocator template parameters in the STL are examples of bad/'burdening' design?
What is the advantage of the function<T,A> interface anyway?
Um...to choose: - on-empty behaviour - size of the SBO buffer - 'decoration' of the boost::function instance (for example whether it is/holds nothrow targets) - default allocator ... IOW: if I want to have a pink flying elephant on my screen every time an empty boost::function<> is invoked, than let me have my pink flying elephant! (... >without< having to wrap or reimplement boost::function ...)
The point is, AFAIK, to erase the type of the object you put into a boost::function<> instance, not the type of boost::function itself...after all unlike in Objective-C(++) in C++ everything has _some_ type in the end...
Everything has a type, but the user doesn't have to know the type of everything.
Neither does (s)he have to not know the type of everything... I'm sorry if I missed some deeper point but this just seems like more of the old "running in circles"...let's not do that please... -- "What Huxley teaches is that in the age of advanced technology, spiritual devastation is more likely to come from an enemy with a smiling face than from one whose countenance exudes suspicion and hate." Neil Postman

On Tue, Oct 19, 2010 at 4:11 AM, Emil Dotchevski <emil@revergestudios.com> wrote:
Because function<T,A1> is not the same type as function<T,A2>.
You can make them pretty convertable by overloading constructors and casting operators. And/or a common base type. I would like to be able to specify the SBO size. ie function<T, 12> and function<T, 16>. But be able to pass it around to anything that expects a function<T>. Surely we should be able to make that work efficiently? Tony
participants (7)
-
Daniel Walker
-
Domagoj Saric
-
Domagoj Saric
-
Emil Dotchevski
-
Gottlob Frege
-
Nevin Liber
-
OvermindDL1