[function] function wrapping with no exception safety guarantee

Hi all, A few weeks ago, there was a request to remove boost::function's dependency on boost::throw_exception when the user ensures that boost::function is always initialized before attempting a call. https://svn.boost.org/trac/boost/ticket/4646 Providing an alternative invocation method in addition to the call operator is an unattractive solution for many reasons; e.g. boost::function would be less function-like syntacticly. Instead, why not provide an alternative function wrapper with no exception safety guarantee and no dependency on boost::throw_exception? Thanks to Boost.Function's implementation design, which uses preprocessor metaprogramming to generate many function wrappers with different arities, it is simple to generate a function wrapper with no exception safety guarantee. I have submitted a feature request with a patch that implements boost::unsafe_function -- a function wrapper with no exception safety guarantee -- along with tests and updated documentation. https://svn.boost.org/trac/boost/ticket/4720 unsafe_function's API and semantics are identical to boost::function except that the behavior of operator() is undefined when uninitialized. Also, swap, constructor and assignment operators have been added to allow an unsafe_function to wrap the target of a boost::function and vice versa. unsafe_function is primarily useful in certain environments in which exceptions and/or compiler optimizations are unavailable, such as some embedded systems. On contemporary PC hardware, unsafe_function typically would not have an advantage over boost::function. For example, with object code generated by gcc -O2, I could only detect a ~1% difference between the two in terms of runtime costs using a simple benchmark; i.e. less than a nanosecond. However, with -O1, unsafe_function costs ~15% less than boost::function due to the lack of overhead from the strong exception safety guarantee. Thoughts? Daniel Walker

Another solution is to define a different constructor of boost::function which initializes it in a way that it doesn't throw, similar to the constructors I added some time ago to support allocators. So you could just say boost::function<void()>(foo,nothrow). Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode On Thu, Oct 7, 2010 at 12:19 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Hi all, A few weeks ago, there was a request to remove boost::function's dependency on boost::throw_exception when the user ensures that boost::function is always initialized before attempting a call.
https://svn.boost.org/trac/boost/ticket/4646
Providing an alternative invocation method in addition to the call operator is an unattractive solution for many reasons; e.g. boost::function would be less function-like syntacticly. Instead, why not provide an alternative function wrapper with no exception safety guarantee and no dependency on boost::throw_exception?
Thanks to Boost.Function's implementation design, which uses preprocessor metaprogramming to generate many function wrappers with different arities, it is simple to generate a function wrapper with no exception safety guarantee. I have submitted a feature request with a patch that implements boost::unsafe_function -- a function wrapper with no exception safety guarantee -- along with tests and updated documentation.
https://svn.boost.org/trac/boost/ticket/4720
unsafe_function's API and semantics are identical to boost::function except that the behavior of operator() is undefined when uninitialized. Also, swap, constructor and assignment operators have been added to allow an unsafe_function to wrap the target of a boost::function and vice versa.
unsafe_function is primarily useful in certain environments in which exceptions and/or compiler optimizations are unavailable, such as some embedded systems. On contemporary PC hardware, unsafe_function typically would not have an advantage over boost::function. For example, with object code generated by gcc -O2, I could only detect a ~1% difference between the two in terms of runtime costs using a simple benchmark; i.e. less than a nanosecond. However, with -O1, unsafe_function costs ~15% less than boost::function due to the lack of overhead from the strong exception safety guarantee.
Thoughts?
Daniel Walker _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On Thu, Oct 7, 2010 at 1:48 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
Another solution is to define a different constructor of boost::function which initializes it in a way that it doesn't throw, similar to the constructors I added some time ago to support allocators. So you could just say boost::function<void()>(foo,nothrow).
That 'feels' compile-time based, requiring a check, the first email is indicating something where there is no check at all, all done at compile-time, that is what I find most useful.

On Thu, Oct 7, 2010 at 8:06 PM, OvermindDL1 <overminddl1@gmail.com> wrote:
On Thu, Oct 7, 2010 at 1:48 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
Another solution is to define a different constructor of boost::function which initializes it in a way that it doesn't throw, similar to the constructors I added some time ago to support allocators. So you could just say boost::function<void()>(foo,nothrow).
That 'feels' compile-time based, requiring a check, the first email is indicating something where there is no check at all, all done at compile-time, that is what I find most useful.
Right, unsafe_function provides no guarantee of how it will behave when it has no target, and in fact, it does not check if it is initialized before attempting to call its target. Hence the name "unsafe." And you're also correct that users can choose between a strong exception safety guarantee or no exception safety guarantee by selecting different types of function object wrappers, either boost::function or unsafe_function, at compile time. However, the two wrappers are cross-constructable (and swappable), so you can also change exception safety levels at runtime. For example, void do_stuff(boost::function<int(int)> f) { // ... if(f) { // Remove the exception safety guarantee for this block. boost::unsafe_function<int(int)> g = f; for(int i = 0; i < INT_MAX; ++i) g(i); } // ... } Emil's suggestion does something similar by changing boost::function's exception safety guarantee, but do we really want to change boost::function's exception safety guarantee? ... For one thing, given an instance of boost::function, you would have to find out how it was constructed in order to know its semantics. However, if the new exception safety level is provided through an alternative wrapper, you can simply look at the type of a wrapped function to know its exception safety guarantee. So, in this case, I would prefer to extend the Boost.Function library through a new function object wrapper, rather than altering the semantics of boost::function. Daniel Walker

Daniel Walker wrote:
void do_stuff(boost::function<int(int)> f) { // ... if(f) { // Remove the exception safety guarantee for this block. boost::unsafe_function<int(int)> g = f; for(int i = 0; i < INT_MAX; ++i) g(i); } // ... }
This example implies that unsafe_function is inherently more efficient, but this need not be so. An empty function may point to throw_bad_function_call instead of NULL.

On Thu, Oct 7, 2010 at 7:22 PM, Peter Dimov <pdimov@pdimov.com> wrote:
Daniel Walker wrote:
void do_stuff(boost::function<int(int)> f) { // ... if(f) { // Remove the exception safety guarantee for this block. boost::unsafe_function<int(int)> g = f; for(int i = 0; i < INT_MAX; ++i) g(i); } // ... }
This example implies that unsafe_function is inherently more efficient, but this need not be so. An empty function may point to throw_bad_function_call instead of NULL.
That is what I recommended in another thread, that instead of an empty function pointer it points to a static global function that asserts or throws or something, possibly user-definable. So a default-constructed function should always point to that static function or so.

On Thu, Oct 7, 2010 at 6:22 PM, Peter Dimov <pdimov@pdimov.com> wrote:
Daniel Walker wrote:
void do_stuff(boost::function<int(int)> f) { // ... if(f) { // Remove the exception safety guarantee for this block. boost::unsafe_function<int(int)> g = f; for(int i = 0; i < INT_MAX; ++i) g(i); } // ... }
This example implies that unsafe_function is inherently more efficient, but this need not be so. An empty function may point to throw_bad_function_call instead of NULL.
Right, and what the empty boost::function does needs not be decided at compile time, it can be done in the constructor. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 I think this is great, for selfish reasons. I'm currently working on a project that uses the clang and LLVM API. clang and LLVM coding conventions are to compile w/o exceptions and without RTTI. I'm able to compile the Boost that I use (Spirit/Proto/Fusion + deps mostly) without RTTI (after a minor fix to the provided Boost workaround), but getting jazz to compile without exceptions is a larger task. This would make it easier. clang and LLVM do not use exceptions and RTTI because they found that compiling without these two features decreases binary size and increased runtime speed. Given how popular clang and LLVM are, I think any changes that Boost can make to reduce RTTI/exception dependencies without decreasing the functionality or portability of Boost would be good for adoption. - -- Bryce Lelbach aka wash http://groups.google.com/group/ariel_devel -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) iEYEARECAAYFAkyuhaAACgkQO/fqqIuE2t4y+ACdH6SlRdZZEV9rI55lO2HO74ir M6kAn0D2MmG/gZK4Y73s6BI3NJOwosNh =Y14x -----END PGP SIGNATURE-----

On Thu, Oct 7, 2010 at 8:37 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Thu, Oct 7, 2010 at 6:22 PM, Peter Dimov <pdimov@pdimov.com> wrote:
Daniel Walker wrote:
void do_stuff(boost::function<int(int)> f) { // ... if(f) { // Remove the exception safety guarantee for this block. boost::unsafe_function<int(int)> g = f; for(int i = 0; i < INT_MAX; ++i) g(i); } // ... }
This example implies that unsafe_function is inherently more efficient, but this need not be so. An empty function may point to throw_bad_function_call instead of NULL.
Right, and what the empty boost::function does needs not be decided at compile time, it can be done in the constructor.
However the empty built-in Boost.Function still does an if(isnull) test on every operator call, whether you assigned something in the constructor or not...

On Thu, Oct 7, 2010 at 7:56 PM, OvermindDL1 <overminddl1@gmail.com> wrote:
On Thu, Oct 7, 2010 at 8:37 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Thu, Oct 7, 2010 at 6:22 PM, Peter Dimov <pdimov@pdimov.com> wrote:
Daniel Walker wrote:
void do_stuff(boost::function<int(int)> f) { // ... if(f) { // Remove the exception safety guarantee for this block. boost::unsafe_function<int(int)> g = f; for(int i = 0; i < INT_MAX; ++i) g(i); } // ... }
This example implies that unsafe_function is inherently more efficient, but this need not be so. An empty function may point to throw_bad_function_call instead of NULL.
Right, and what the empty boost::function does needs not be decided at compile time, it can be done in the constructor.
However the empty built-in Boost.Function still does an if(isnull) test on every operator call, whether you assigned something in the constructor or not...
Like Peter said, this need not be the case. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

"Bryce Lelbach" <admin@thefireflyproject.us> wrote in message news:20101007224448.75308cb8@Pegasus...
I think this is great, for selfish reasons. I'm currently working on a project that uses the clang and LLVM API. clang and LLVM coding conventions are to compile w/o exceptions and without RTTI. I'm able to compile the Boost that I use (Spirit/Proto/Fusion + deps mostly) without RTTI (after a minor fix to the provided Boost workaround), but getting jazz to compile without exceptions is a larger task. This would make it easier.
Ability to turn off RTTI, specify on-empty policy which uses target functors instead of if-empty-then (with provided assert-on-empty, throw-on-empty and nop-on-empty handlers/functors), work w/o exceptions or work in an exception-enabled environment but only mark itself as a nothrow function, as well as many other improvements (reduced template bloat, compiler-specific optimizations, etc.) is already done (in an alpha-msvc only state): https://svn.boost.org/svn/boost/sandbox/function/boost/function http://article.gmane.org/gmane.comp.lib.boost.devel/195351 ... Considering that interest again seems to be on the rise, maybe Doug Gregor will finally find the time to go through all/some of these proposals and that some changes will finally be made...and I might also finally finish my code/changes now that I've started working with GCC... -- "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 Fri, Oct 8, 2010 at 4:45 AM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Bryce Lelbach" <admin@thefireflyproject.us> wrote in message news:20101007224448.75308cb8@Pegasus...
I think this is great, for selfish reasons. I'm currently working on a project that uses the clang and LLVM API. clang and LLVM coding conventions are to compile w/o exceptions and without RTTI. I'm able to compile the Boost that I use (Spirit/Proto/Fusion + deps mostly) without RTTI (after a minor fix to the provided Boost workaround), but getting jazz to compile without exceptions is a larger task. This would make it easier.
Ability to turn off RTTI, specify on-empty policy which uses target functors instead of if-empty-then (with provided assert-on-empty, throw-on-empty and nop-on-empty handlers/functors), work w/o exceptions or work in an exception-enabled environment but only mark itself as a nothrow function, as well as many other improvements (reduced template bloat, compiler-specific optimizations, etc.) is already done (in an alpha-msvc only state): https://svn.boost.org/svn/boost/sandbox/function/boost/function http://article.gmane.org/gmane.comp.lib.boost.devel/195351 ...
Considering that interest again seems to be on the rise, maybe Doug Gregor will finally find the time to go through all/some of these proposals and that some changes will finally be made...and I might also finally finish my code/changes now that I've started working with GCC...
I haven't taken the time to look at your project yet either, but thanks for reminding the list that it's available in the sandbox. I have to say that I don't find the idea of gutting the current implementation to be particularly attractive. Boost.Function is already proven and familiar, and there's more we can still do with it. Plus, it takes time to study a lot of new code. Daniel Walker

"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTikdt4Cx9QcqeUX=SZ9rB8uqrmaahLpfMgxtEkTv@mail.gmail.com...
I have to say that I don't find the idea of gutting the current implementation to be particularly attractive. Boost.Function is already proven and familiar, and there's more we can still do with it.
We can do more with it w/o 'gutting' it? I'm sorry I do not understand why unsafe_function does not constitute 'gutting' while my changes do...note that 'my' function requires no macro or a different name and is backwards compatible with existing code (it only needs to be recompiled)...
Plus, it takes time to study a lot of new code.
Ideally this should not be an argument as it takes time to do anything (right)...
I don't believe efficiency is a significant issue. I tried to measure the difference in performance between boost::function and unsafe_function in a tight loop, and with gcc -02, the difference is on the order of hundreds of picoseconds; i.e. in optimized code on contemporary PC hardware, unsafe_function is not significantly more efficient. But of course, results will vary according to your optimizer.
Just to clear something first, it seems to me you misunderstood the meaning of the exception safety guarantee which AFAICT has nothing to do with your proposal: http://en.wikipedia.org/wiki/Exception_guarantees Your modification only eliminates the if-not-then branching overhead which, yes, can be almost completely removed by a powerful enough optimizer in some circumstances, e.g. if operator() is inlined and the function object is repeatedly called in a simple loop as is the case in a typical and simple synthetic benchmark... However this still does nothing concerning the exceptions vs no-exceptions comparison/debate because the compiler still has to treat function<>::operator() as a possibly throwing function (and add/generate appropriate EH code in/for the callers) because it makes an indirect call through a (undecorated) pointer... However, here http://lists.boost.org/Archives/boost/2010/01/160908.php you can see results that show a measurable difference when function<> is configured to mark itself as nothrow... Note that not all compilers implement exception handling with the theoretical 'bloat-but-no-time' overhead...among those is also MSVC++ (all versions) when targeting 32 bit x86 (which is still the dominant compiler-platform combination) which also introduces a run-time overhead and the presence of EH states in a function seriously hinders its optimizer for some typical tasks (such as inlining and NVRO)... -- "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:43 AM, Domagoj Saric <domagoj.saric@littleendian.com> wrote:
However this still does nothing concerning the exceptions vs no-exceptions comparison/debate because the compiler still has to treat function<>::operator() as a possibly throwing function (and add/generate appropriate EH code in/for the callers) because it makes an indirect call through a (undecorated) pointer...
If you don't disable exception handling, the compiler must treat the dynamic call in boost::function as potentially throwing. There is no way around that. (If you do disable exception handling, boost::function already does not throw. It still depends on Boost Exception, but only because that is where the common workarounds for dealing with BOOST_NO_EXCEPTIONS live; that is, BOOST_NO_EXCEPTIONS is a valid configuration for the Boost Exception library.) Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On 11 October 2010 12:21, Emil Dotchevski <emil@revergestudios.com> wrote:
If you don't disable exception handling, the compiler must treat the dynamic call in boost::function as potentially throwing. There is no way around that.
(If you do disable exception handling, boost::function already does not throw.
Given all that, is there any more to this proposal than to take the previously well defined behavior of calling an "empty" function and making it undefined behavior (and not for the purpose of optimization)? Since "undefined behavior" pretty much means we can do whatever we want, don't we already meet that definition? -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404

On Mon, Oct 11, 2010 at 1:38 PM, Nevin Liber <nevin@eviloverlord.com> wrote:
On 11 October 2010 12:21, Emil Dotchevski <emil@revergestudios.com> wrote:
If you don't disable exception handling, the compiler must treat the dynamic call in boost::function as potentially throwing. There is no way around that.
(If you do disable exception handling, boost::function already does not throw.
Given all that, is there any more to this proposal than to take the previously well defined behavior of calling an "empty" function and making it undefined behavior (and not for the purpose of optimization)?
Correct. unsafe_function is the same as boost::function except that its behavior is undefined when it has no target. In this way, it behaves more like a function pointer than boost::function, which is desirable for projects that do not use RTTI (and don't want to bother configuring Boost.Exception, which is understandable). unsafe_function works out-of-the-box in RTTI-free environments; boost::function does not due to its strong exception safety guarantee.
Since "undefined behavior" pretty much means we can do whatever we want, don't we already meet that definition?
By "undefined behavior" I mean we do not define the behavior in the event that the pre-conditions of operator() are not met. And indeed, we cannot define the behavior in any platform independent way, because it involves dereferencing a null pointer. Daniel Walker

At Mon, 11 Oct 2010 10:21:10 -0700, Emil Dotchevski wrote:
On Mon, Oct 11, 2010 at 7:43 AM, Domagoj Saric <domagoj.saric@littleendian.com> wrote:
However this still does nothing concerning the exceptions vs no-exceptions comparison/debate because the compiler still has to treat function<>::operator() as a possibly throwing function (and add/generate appropriate EH code in/for the callers) because it makes an indirect call through a (undecorated) pointer...
If you don't disable exception handling, the compiler must treat the dynamic call in boost::function as potentially throwing. There is no way around that.
Well, technically, an exception-specification of throw() relieves the compiler from such an assumption. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTi=5z+8LYDTAPLSaivGRsvGX0BoOw0bhpFrzoYCX@mail.gmail.com...
On Mon, Oct 11, 2010 at 7:43 AM, Domagoj Saric <domagoj.saric@littleendian.com> wrote:
However this still does nothing concerning the exceptions vs no-exceptions comparison/debate because the compiler still has to treat function<>::operator() as a possibly throwing function (and add/generate appropriate EH code in/for the callers) because it makes an indirect call through a (undecorated) pointer...
If you don't disable exception handling, the compiler must treat the dynamic call in boost::function as potentially throwing. There is no way around that.
Of course there is, as I've shown performance difference results (repeated link http://lists.boost.org/Archives/boost/2010/01/160908.php) that also include data for the case when the 'way around' is turned on... The way around, as David has hinted, is the decoration of the pointer itself or the operator() (MSVC++ __declspec( nothrow ), GCC __attribute__(( nothrow )), c++1x noexcept, non-standard/'optimized' throw()...)... -- "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 10:43 AM, Domagoj Saric <domagoj.saric@littleendian.com> wrote:
"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTikdt4Cx9QcqeUX=SZ9rB8uqrmaahLpfMgxtEkTv@mail.gmail.com...
I have to say that I don't find the idea of gutting the current implementation to be particularly attractive. Boost.Function is already proven and familiar, and there's more we can still do with it.
We can do more with it w/o 'gutting' it? I'm sorry I do not understand why unsafe_function does not constitute 'gutting' while my changes do...note that 'my' function requires no macro or a different name and is backwards compatible with existing code (it only needs to be recompiled)...
My patch is very simple, and there are very few changes to the existing code. It uses the existing preprocessor metaprogramming infrastructure of Boost.Function to generate the same implementation code for both boost::function and unsafe_function with one small exception: The guarantee that operator() throws when it has no target is removed from unsafe_function. So, the vast majority of the implementation (type-erasure management, etc.) is unchanged.
Plus, it takes time to study a lot of new code.
Ideally this should not be an argument as it takes time to do anything (right)...
I only offer that statement as an explanation for why rewrites of familiar projects are often not embraced. It takes time for people to study the new implementation. If the current implementation is already trusted, then there is less incentive to invest time in studying a new implementation.
I don't believe efficiency is a significant issue. I tried to measure the difference in performance between boost::function and unsafe_function in a tight loop, and with gcc -02, the difference is on the order of hundreds of picoseconds; i.e. in optimized code on contemporary PC hardware, unsafe_function is not significantly more efficient. But of course, results will vary according to your optimizer.
Just to clear something first, it seems to me you misunderstood the meaning of the exception safety guarantee which AFAICT has nothing to do with your proposal: http://en.wikipedia.org/wiki/Exception_guarantees
unsafe_function offers no exception guarantee. In the wiki's terminology, it would be called "exception unsafe." Hence the name.
<snip> However, here http://lists.boost.org/Archives/boost/2010/01/160908.php you can see results that show a measurable difference when function<> is configured to mark itself as nothrow...
The goal of unsafe_function is not to provide a wrapper that doesn't throw, but to provide a wrapper with no exception safety guarantee. Daniel Walker

At Mon, 11 Oct 2010 14:19:31 -0400, Daniel Walker wrote:
On Mon, Oct 11, 2010 at 10:43 AM, Domagoj Saric <domagoj.saric@littleendian.com> wrote:
"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTikdt4Cx9QcqeUX=SZ9rB8uqrmaahLpfMgxtEkTv@mail.gmail.com...
I have to say that I don't find the idea of gutting the current implementation to be particularly attractive. Boost.Function is already proven and familiar, and there's more we can still do with it.
We can do more with it w/o 'gutting' it? I'm sorry I do not understand why unsafe_function does not constitute 'gutting' while my changes do...note that 'my' function requires no macro or a different name and is backwards compatible with existing code (it only needs to be recompiled)...
My patch is very simple, and there are very few changes to the existing code. It uses the existing preprocessor metaprogramming infrastructure of Boost.Function to generate the same implementation code for both boost::function and unsafe_function with one small exception: The guarantee that operator() throws when it has no target is removed from unsafe_function. So, the vast majority of the implementation (type-erasure management, etc.) is unchanged.
I'm sorry if I missed something important here, but has everybody really considered the consequences of Peter Dimov's post, where he wrote:
This example implies that unsafe_function is inherently more efficient, but this need not be so. An empty function may point to throw_bad_function_call instead of NULL.
One could swap out throw_bad_function_call for any behavior you like.
<snip> However, here http://lists.boost.org/Archives/boost/2010/01/160908.php you can see results that show a measurable difference when function<> is configured to mark itself as nothrow...
The goal of unsafe_function is not to provide a wrapper that doesn't throw, but to provide a wrapper with no exception safety guarantee.
If that's *really* its goal, unsafe_function is strictly unneeded. boost::function already satisfies all your requirements (and more). I think if you're looking to supply motivation for unsafe_function, you'll need to describe the goal differently. ;-) -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Tue, Oct 12, 2010 at 3:44 AM, David Abrahams <dave@boostpro.com> wrote:
At Mon, 11 Oct 2010 14:19:31 -0400, Daniel Walker wrote:
On Mon, Oct 11, 2010 at 10:43 AM, Domagoj Saric <domagoj.saric@littleendian.com> wrote:
"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTikdt4Cx9QcqeUX=SZ9rB8uqrmaahLpfMgxtEkTv@mail.gmail.com...
I have to say that I don't find the idea of gutting the current implementation to be particularly attractive. Boost.Function is already proven and familiar, and there's more we can still do with it.
We can do more with it w/o 'gutting' it? I'm sorry I do not understand why unsafe_function does not constitute 'gutting' while my changes do...note that 'my' function requires no macro or a different name and is backwards compatible with existing code (it only needs to be recompiled)...
My patch is very simple, and there are very few changes to the existing code. It uses the existing preprocessor metaprogramming infrastructure of Boost.Function to generate the same implementation code for both boost::function and unsafe_function with one small exception: The guarantee that operator() throws when it has no target is removed from unsafe_function. So, the vast majority of the implementation (type-erasure management, etc.) is unchanged.
I'm sorry if I missed something important here, but has everybody really considered the consequences of Peter Dimov's post, where he wrote:
This example implies that unsafe_function is inherently more efficient, but this need not be so. An empty function may point to throw_bad_function_call instead of NULL.
One could swap out throw_bad_function_call for any behavior you like.
unsafe_function is not inherently more efficient. In optimized object code (gcc -02 or MSVC Release mode) the difference between invoking unsafe_function or boost::function is minuscule (on the order of hundreds of picoseconds). Peter's post similarly relies on removing the NULL pointer check for performance gains. This may be a good idea or it may be a case of premature optimization; whether or not it improves performance depends on the compiler's optimization. But either way, efficiency is tangential to the issue of boost::function's dependency on Boost.Exception. Also, swapping out throw_bad_function call does not directly address the boost::function/Boost.Exception coupling issue. If boost::function is going to offer a strong exception safety guarantee, then I believe Boost.Exception is the best way to implement that guarantee, no matter how boost::function gets around to calling boost::throw_exception. (I also think boost::function should continue to offer the strong guarantee.) But some users are asking for a function object wrapper that is not coupled with Boost.Exception. The simplest way to decouple them is to provide a function object wrapper without the strong exception safety guarantee.
<snip> However, here http://lists.boost.org/Archives/boost/2010/01/160908.php you can see results that show a measurable difference when function<> is configured to mark itself as nothrow...
The goal of unsafe_function is not to provide a wrapper that doesn't throw, but to provide a wrapper with no exception safety guarantee.
If that's *really* its goal, unsafe_function is strictly unneeded. boost::function already satisfies all your requirements (and more).
boost::function always provides a strong exception safety guarantee. Specifically, if its preconditions are not met, it calls boost::throw_exception. This is true whether or not the system has RTTI. This is great for some users, but others have asked for a function object wrapper that does not call boost::throw_exception. A simple way to meet this requirement is to provide a function object wrapper that is exception unsafe, like a typical function pointer for example, and that is what unsafe_function does.
I think if you're looking to supply motivation for unsafe_function, you'll need to describe the goal differently. ;-)
How about this. Typically, function pointers have no RTTI dependency (and no dependency on Boost.Exception) and are exception unsafe. unsafe_function is a function object wrapper that behaves more like a function pointer with respect to exception safety. Daniel Walker

On Tue, Oct 12, 2010 at 10:48 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
At Mon, 11 Oct 2010 14:19:31 -0400, Daniel Walker wrote: swapping out throw_bad_function call does not directly address
On Tue, Oct 12, 2010 at 3:44 AM, David Abrahams <dave@boostpro.com> wrote: the boost::function/Boost.Exception coupling issue.
It could be implemented such that the dependency on boost::throw_exception is only there if the default throwing behavior is used. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

At Tue, 12 Oct 2010 13:48:37 -0400, Daniel Walker wrote:
I'm sorry if I missed something important here, but has everybody really considered the consequences of Peter Dimov's post, where he wrote:
This example implies that unsafe_function is inherently more efficient, but this need not be so. An empty function may point to throw_bad_function_call instead of NULL.
One could swap out throw_bad_function_call for any behavior you like.
unsafe_function is not inherently more efficient. In optimized object code (gcc -02 or MSVC Release mode) the difference between invoking unsafe_function or boost::function is minuscule (on the order of hundreds of picoseconds). Peter's post similarly relies on removing the NULL pointer check for performance gains. This may be a good idea or it may be a case of premature optimization; whether or not it improves performance depends on the compiler's optimization. But either way, efficiency is tangential to the issue of boost::function's dependency on Boost.Exception.
Is *that* the core issue here? Because it seems like the issue has been about various other things earlier in this conversation.
Also, swapping out throw_bad_function call does not directly address the boost::function/Boost.Exception coupling issue. If boost::function is going to offer a strong exception safety guarantee, then I believe Boost.Exception is the best way to implement that guarantee, no matter how boost::function gets around to calling boost::throw_exception. (I also think boost::function should continue to offer the strong guarantee.)
Which operation of boost::function are you talking about, that offers the strong guarantee? And how can Boost.Exception be a way to achieve the strong guarantee?
But some users are asking for a function object wrapper that is not coupled with Boost.Exception.
Why?
The simplest way to decouple them is to provide a function object wrapper without the strong exception safety guarantee.
<snip> However, here http://lists.boost.org/Archives/boost/2010/01/160908.php you can see results that show a measurable difference when function<> is configured to mark itself as nothrow...
The goal of unsafe_function is not to provide a wrapper that doesn't throw, but to provide a wrapper with no exception safety guarantee.
If that's *really* its goal, unsafe_function is strictly unneeded. boost::function already satisfies all your requirements (and more).
boost::function always provides a strong exception safety guarantee. Specifically, if its preconditions are not met, it calls boost::throw_exception.
That's not strong exception-safety. That's throwing an exception where an assert belongs. :-(
This is true whether or not the system has RTTI. This is great for some users, but others have asked for a function object wrapper that does not call boost::throw_exception. A simple way to meet this requirement is to provide a function object wrapper that is exception unsafe, like a typical function pointer for example, and that is what unsafe_function does.
IMO a better way to do it would be to make a function object that has no empty state.
I think if you're looking to supply motivation for unsafe_function, you'll need to describe the goal differently. ;-)
How about this. Typically, function pointers have no RTTI dependency (and no dependency on Boost.Exception) and are exception unsafe.
In what sense are function pointers exception-unsafe?!
unsafe_function is a function object wrapper that behaves more like a function pointer with respect to exception safety.
I am beginning to think you have a different definition of exception safety from the rest of the world. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Tue, Oct 12, 2010 at 2:09 PM, David Abrahams <dave@boostpro.com> wrote:
At Tue, 12 Oct 2010 13:48:37 -0400, Daniel Walker wrote:
I'm sorry if I missed something important here, but has everybody really considered the consequences of Peter Dimov's post, where he wrote:
This example implies that unsafe_function is inherently more efficient, but this need not be so. An empty function may point to throw_bad_function_call instead of NULL.
One could swap out throw_bad_function_call for any behavior you like.
unsafe_function is not inherently more efficient. In optimized object code (gcc -02 or MSVC Release mode) the difference between invoking unsafe_function or boost::function is minuscule (on the order of hundreds of picoseconds). Peter's post similarly relies on removing the NULL pointer check for performance gains. This may be a good idea or it may be a case of premature optimization; whether or not it improves performance depends on the compiler's optimization. But either way, efficiency is tangential to the issue of boost::function's dependency on Boost.Exception.
Is *that* the core issue here? Because it seems like the issue has been about various other things earlier in this conversation.
That's my interpretation of the core issue. Efficiency seems like a side issue to me since in optimized object code operator() seems to run in about the same amount of time with or with out the NULL pointer check.
Also, swapping out throw_bad_function call does not directly address the boost::function/Boost.Exception coupling issue. If boost::function is going to offer a strong exception safety guarantee, then I believe Boost.Exception is the best way to implement that guarantee, no matter how boost::function gets around to calling boost::throw_exception. (I also think boost::function should continue to offer the strong guarantee.)
Which operation of boost::function are you talking about, that offers the strong guarantee? And how can Boost.Exception be a way to achieve the strong guarantee?
operator() offers a strong guarantee in that it either calls the target or calls boost::throw_exception. I don't mean Boost.Exception is used to "achieve" the guarantee, but to implement it; i.e. in the case where the wrapper is empty, boost::throw_excpetion can be used instead of a throw statement. This is preferable because it allows the exception to be reported with or without RTTI.
But some users are asking for a function object wrapper that is not coupled with Boost.Exception.
Why?
Some users who do not use RTTI (e.g. on some embedded system), do not want to take the time to configure Boost.Exception for their platform, and without configuring Boost.Exception, they get unexpected link errors, because boost::throw_exception is undefined.
The simplest way to decouple them is to provide a function object wrapper without the strong exception safety guarantee.
<snip> However, here http://lists.boost.org/Archives/boost/2010/01/160908.php you can see results that show a measurable difference when function<> is configured to mark itself as nothrow...
The goal of unsafe_function is not to provide a wrapper that doesn't throw, but to provide a wrapper with no exception safety guarantee.
If that's *really* its goal, unsafe_function is strictly unneeded. boost::function already satisfies all your requirements (and more).
boost::function always provides a strong exception safety guarantee. Specifically, if its preconditions are not met, it calls boost::throw_exception.
That's not strong exception-safety. That's throwing an exception where an assert belongs. :-(
I'm using the following definition of strong exception safety. "The strong guarantee: that the operation has either completed successfully or thrown an exception, leaving the program state exactly as it was before the operation started." http://www.boost.org/community/exception_safety.html I suppose there is a nuance here in that the target function could throw, so more formally we could say boost::function has strong exception safety if the target function has strong exception safety. Here the definition of the phrase "thrown an exception" depends on the definition of boost::throw_exception, which is user customizable.
This is true whether or not the system has RTTI. This is great for some users, but others have asked for a function object wrapper that does not call boost::throw_exception. A simple way to meet this requirement is to provide a function object wrapper that is exception unsafe, like a typical function pointer for example, and that is what unsafe_function does.
IMO a better way to do it would be to make a function object that has no empty state.
I'm amenable to that. What would you call it?
I think if you're looking to supply motivation for unsafe_function, you'll need to describe the goal differently. ;-)
How about this. Typically, function pointers have no RTTI dependency (and no dependency on Boost.Exception) and are exception unsafe.
In what sense are function pointers exception-unsafe?!
Their behavior is undefined when they are null; i.e. when they are invoked they offer neither a basic, strong nor nothrow guarantee.
unsafe_function is a function object wrapper that behaves more like a function pointer with respect to exception safety.
I am beginning to think you have a different definition of exception safety from the rest of the world.
Well, it's important to use similar definitions. I'm trying to stick to the definition above. How can I do this better? Daniel Walker

On 12 October 2010 14:14, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Some users who do not use RTTI (e.g. on some embedded system), do not want to take the time to configure Boost.Exception for their platform, and without configuring Boost.Exception, they get unexpected link errors, because boost::throw_exception is undefined.
In other words, Boost is misconfigured on their system. What guarantees are there for *any* Boost library to work correctly under these circumstances? -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404

At Tue, 12 Oct 2010 15:14:58 -0400, Daniel Walker wrote:
On Tue, Oct 12, 2010 at 2:09 PM, David Abrahams <dave@boostpro.com> wrote:
At Tue, 12 Oct 2010 13:48:37 -0400, Daniel Walker wrote:
Also, swapping out throw_bad_function call does not directly address the boost::function/Boost.Exception coupling issue. If boost::function is going to offer a strong exception safety guarantee, then I believe Boost.Exception is the best way to implement that guarantee, no matter how boost::function gets around to calling boost::throw_exception. (I also think boost::function should continue to offer the strong guarantee.)
Which operation of boost::function are you talking about, that offers the strong guarantee? And how can Boost.Exception be a way to achieve the strong guarantee?
operator() offers a strong guarantee in that it either calls the target or calls boost::throw_exception.
That isn't the strong guarantee; it's just part of the class's non-exceptional semantics. The strong guarantee has to do with what happens *when* an exception is thrown. You should stop using the term that way unless you want to confuse everybody.
I don't mean Boost.Exception is used to "achieve" the guarantee, but to implement it; i.e. in the case where the wrapper is empty, boost::throw_excpetion can be used instead of a throw statement. This is preferable because it allows the exception to be reported with or without RTTI.
Okay.
But some users are asking for a function object wrapper that is not coupled with Boost.Exception.
Why?
Some users who do not use RTTI (e.g. on some embedded system),
I think that's irrelevant. Actually RTTI and EH are orthogonal in principle, though they use similar mechanisms and some compiler vendors may tie them together. In any case Boost.Exception can be configured not to use it.
do not want to take the time to configure Boost.Exception for their platform, and without configuring Boost.Exception, they get unexpected link errors, because boost::throw_exception is undefined.
If users are going to use a subset of C++, they should not be too surprised that they have to add a -D option to their command-line to keep everything linking. Avoiding that is certainly not worth the cost of supporting a parallel copy of boost::function.
boost::function always provides a strong exception safety guarantee. Specifically, if its preconditions are not met, it calls boost::throw_exception.
That's not strong exception-safety. That's throwing an exception where an assert belongs. :-(
I'm using the following definition of strong exception safety.
"The strong guarantee: that the operation has either completed successfully or thrown an exception, leaving the program state exactly as it was before the operation started."
Yes, I invented the term and wrote that definition, but no, you're not using it properly. All constructors with no side-effects offer the strong guarantee, by the way. So asserting that a constructor offers the strong guarantee is not very meaningful once you know that the constructor's semantics are side-effect free.
I suppose there is a nuance here in that the target function could throw, so more formally we could say boost::function has strong exception safety if the target function has strong exception safety.
Sorry, but that makes no sense. Classes don't have strong exception-safety. Only operations do.
Here the definition of the phrase "thrown an exception" depends on the definition of boost::throw_exception, which is user customizable.
I don't think you can redefine the phrase “throws an exception” to mean something that might not throw an exception, and still communicate effectively here.
This is true whether or not the system has RTTI. This is great for some users, but others have asked for a function object wrapper that does not call boost::throw_exception. A simple way to meet this requirement is to provide a function object wrapper that is exception unsafe, like a typical function pointer for example, and that is what unsafe_function does.
IMO a better way to do it would be to make a function object that has no empty state.
I'm amenable to that. What would you call it?
nonempty::function ?
I think if you're looking to supply motivation for unsafe_function, you'll need to describe the goal differently. ;-)
How about this. Typically, function pointers have no RTTI dependency (and no dependency on Boost.Exception) and are exception unsafe.
In what sense are function pointers exception-unsafe?!
Their behavior is undefined when they are null; i.e. when they are invoked they offer neither a basic, strong nor nothrow guarantee.
That is *not* exception-unsafe! There are documented preconditions on the function call operator, and you must satisfy them or all bets are off. Almost every operation in std:: has such conditions here or there. That doesn't make them exception-unsafe. Exception-unsafe means that *when* an exception is thrown, invariants are violated (or resources leaked).
unsafe_function is a function object wrapper that behaves more like a function pointer with respect to exception safety.
I am beginning to think you have a different definition of exception safety from the rest of the world.
Well, it's important to use similar definitions. I'm trying to stick to the definition above. How can I do this better?
Other than studying the definitions and taking them literally, I don't know what to suggest. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Tue, Oct 12, 2010 at 4:15 PM, David Abrahams <dave@boostpro.com> wrote:
At Tue, 12 Oct 2010 15:14:58 -0400, Daniel Walker wrote:
On Tue, Oct 12, 2010 at 2:09 PM, David Abrahams <dave@boostpro.com> wrote:
At Tue, 12 Oct 2010 13:48:37 -0400, Daniel Walker wrote:
But some users are asking for a function object wrapper that is not coupled with Boost.Exception.
Why?
Some users who do not use RTTI (e.g. on some embedded system),
I think that's irrelevant. Actually RTTI and EH are orthogonal in principle, though they use similar mechanisms and some compiler vendors may tie them together. In any case Boost.Exception can be configured not to use it.
do not want to take the time to configure Boost.Exception for their platform, and without configuring Boost.Exception, they get unexpected link errors, because boost::throw_exception is undefined.
If users are going to use a subset of C++, they should not be too surprised that they have to add a -D option to their command-line to keep everything linking. Avoiding that is certainly not worth the cost of supporting a parallel copy of boost::function.
Sorry, I may not have been clear. In order to configure Boost.Function to work without RTTI, you need to define a function not a configuration macro. So, there is no -D option. This is part of the reason that some users are frustrated.
boost::function always provides a strong exception safety guarantee. Specifically, if its preconditions are not met, it calls boost::throw_exception.
That's not strong exception-safety. That's throwing an exception where an assert belongs. :-(
I'm using the following definition of strong exception safety.
"The strong guarantee: that the operation has either completed successfully or thrown an exception, leaving the program state exactly as it was before the operation started."
Yes, I invented the term and wrote that definition, but no, you're not using it properly.
OK, thanks for the help. Sorry for the confusion.
All constructors with no side-effects offer the strong guarantee, by the way. So asserting that a constructor offers the strong guarantee is not very meaningful once you know that the constructor's semantics are side-effect free.
I'm only talking about operator(), so I should have said boost::function invocation has strong exception safety, instead of just "boost::function has strong exception safety," which was incorrect usage.
I suppose there is a nuance here in that the target function could throw, so more formally we could say boost::function has strong exception safety if the target function has strong exception safety.
Sorry, but that makes no sense. Classes don't have strong exception-safety. Only operations do.
Right, so I'll rephrase. Formally, boost::function invocation has strong exception safety if invoking the target function has strong exception safety.
Here the definition of the phrase "thrown an exception" depends on the definition of boost::throw_exception, which is user customizable.
I don't think you can redefine the phrase “throws an exception” to mean something that might not throw an exception, and still communicate effectively here.
Yes, this could be confusing. For this to be meaningful you would have to be clear about using boost::throw_exception instead of a throw statement and the reader would need to be familiar with Boost.Exception. But I don't think that's too much to ask.
This is true whether or not the system has RTTI. This is great for some users, but others have asked for a function object wrapper that does not call boost::throw_exception. A simple way to meet this requirement is to provide a function object wrapper that is exception unsafe, like a typical function pointer for example, and that is what unsafe_function does.
IMO a better way to do it would be to make a function object that has no empty state.
I'm amenable to that. What would you call it?
nonempty::function ?
OK, I might try to roll this together. It could be a better solution.
I think if you're looking to supply motivation for unsafe_function, you'll need to describe the goal differently. ;-)
How about this. Typically, function pointers have no RTTI dependency (and no dependency on Boost.Exception) and are exception unsafe.
In what sense are function pointers exception-unsafe?!
Their behavior is undefined when they are null; i.e. when they are invoked they offer neither a basic, strong nor nothrow guarantee.
That is *not* exception-unsafe! There are documented preconditions on the function call operator, and you must satisfy them or all bets are off. Almost every operation in std:: has such conditions here or there. That doesn't make them exception-unsafe. Exception-unsafe means that *when* an exception is thrown, invariants are violated (or resources leaked).
OK. I think I see the confusion here. I was using the exception safety guarantees to describe how an operation behaves when its preconditions are not met, but you use the terms only to describe how an operation behaves when an exception is thrown. With boost::function these are the same events; it throws an exception when its preconditions aren't met. With a function pointer, the system checks the preconditions and may throw an exception or terminate execution with a segfault or whatever. I was trying to make an analogy between invoking an empty function object wrapper and invoking a null function pointer. Anyway, to avoid confusion, I'll stop using this analogy, and I will not use the exception safety guarantees to refer to the behavior of a function pointer invocation.
unsafe_function is a function object wrapper that behaves more like a function pointer with respect to exception safety.
I am beginning to think you have a different definition of exception safety from the rest of the world.
Well, it's important to use similar definitions. I'm trying to stick to the definition above. How can I do this better?
Other than studying the definitions and taking them literally, I don't know what to suggest.
Thanks. I will try to do so. Daniel Walker

On Tue, Oct 12, 2010 at 4:04 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Formally, boost::function invocation has strong exception safety if invoking the target function has strong exception safety.
This makes no sense at all. Invoking boost::function always has strong exception safety guarantee. In no way it can make the state of the boost::function object inconsistent, because it does not modify its state. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Tue, Oct 12, 2010 at 7:22 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Tue, Oct 12, 2010 at 4:04 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Formally, boost::function invocation has strong exception safety if invoking the target function has strong exception safety.
This makes no sense at all. Invoking boost::function always has strong exception safety guarantee. In no way it can make the state of the boost::function object inconsistent, because it does not modify its state.
The target function could dereference a null pointer, which would not only modify the state of boost::function, it would modify the state of the entire system by bringing it to an abrupt halt. So, to be formal, a call to boost::function::operator() will only complete successfully or throw an exception if the target function completes successfully or throws an exception. However, I think, informally, we can leave it unspoken but understood that boost::function's behavior depends on the target function. Daniel Walker

David Abrahams wrote:
Is *that* the core issue here? Because it seems like the issue has been about various other things earlier in this conversation.
The core issue, if I remember correctly, is that when a library uses boost::function internally without ever calling it while NULL and the user compiles with exceptions disabled, he needs to supply a definition of boost::throw_exception even though it will never be called.

On Tue, Oct 12, 2010 at 5:39 PM, Peter Dimov <pdimov@pdimov.com> wrote:
David Abrahams wrote:
Is *that* the core issue here? Because it seems like the issue has been about various other things earlier in this conversation.
The core issue, if I remember correctly, is that when a library uses boost::function internally without ever calling it while NULL and the user compiles with exceptions disabled, he needs to supply a definition of boost::throw_exception even though it will never be called.
Yes, that was the original complaint. The efficiency issue was not the motivation of the feature request, as I understand; it was the coupling issue. But the coupling with Boost.Exception is only there to implement the strong exception safety guarantee of operator(). I thought the simplest solution would be to remove the guarantee, which the user did not want to begin with. Daniel Walker

Daniel Walker wrote:
But the coupling with Boost.Exception is only there to implement the strong exception safety guarantee of operator().
Your terminology is wrong. Both variants of operator() have the same exception safety; and even if they didn't, nobody uses "strong exception safety" to mean "throws an exception when such-and-so". The issue is not coupling with Boost.Exception, the issue is that the user has to supply a definition of boost::throw_exception when exceptions are disabled. This was true before there were Boost.Exception.

On Tue, Oct 12, 2010 at 7:59 PM, Peter Dimov <pdimov@pdimov.com> wrote:
The issue is not coupling with Boost.Exception, the issue is that the user has to supply a definition of boost::throw_exception when exceptions are disabled. This was true before there were Boost.Exception.
Okay, and could someone please explain to me what is wrong with that requirement? -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Tue, Oct 12, 2010 at 6:38 PM, Dave Abrahams <dave@boostpro.com> wrote:
On Tue, Oct 12, 2010 at 7:59 PM, Peter Dimov <pdimov@pdimov.com> wrote:
The issue is not coupling with Boost.Exception, the issue is that the user has to supply a definition of boost::throw_exception when exceptions are disabled. This was true before there were Boost.Exception.
Okay, and could someone please explain to me what is wrong with that requirement?
Maybe someone else should do that but I think I understand it. Suppose you're a subcontractor who develops a library for another company. Internally, you use boost::function and so your library requires the executable to define boost::throw_exception. You could tell the other company to do that, but you'd rather not: at best, you'd have to explain why this is needed even though the function won't be called, at worst they'd be mad that you've used Boost (that's common in games, for example.) Your other option is to define boost::throw_exception in the library, but then if another library uses Boost they'll get link errors. So you'd rather keep everything under wraps. After all, you never, ever call an empty boost::function. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

At Tue, 12 Oct 2010 18:50:13 -0700, Emil Dotchevski wrote:
On Tue, Oct 12, 2010 at 6:38 PM, Dave Abrahams <dave@boostpro.com> wrote:
On Tue, Oct 12, 2010 at 7:59 PM, Peter Dimov <pdimov@pdimov.com> wrote:
The issue is not coupling with Boost.Exception, the issue is that the user has to supply a definition of boost::throw_exception when exceptions are disabled. This was true before there were Boost.Exception.
Okay, and could someone please explain to me what is wrong with that requirement?
Maybe someone else should do that but I think I understand it.
Suppose you're a subcontractor who develops a library for another company. Internally, you use boost::function and so your library requires the executable to define boost::throw_exception.
Ooooh. We don't have a way for the library to define boost::throw_exception. Riiight. I think we could fix that pretty easily, though. Those places in Boost that use boost::throw_exception could switch to something like this: boost::detail::throw_(e); where we define: namespace boost { template <class X, bool=false> struct throw_ { throw_(X const& x) { boost::throw_exception(x); } }; namespace detail { template <class X> throw_(X const& e) { boost::throw_<X>(e); }; } } and then the 3rd-party library author could just: namespace boost { template <class X> struct throw_<X> { throw_(X const&) { /* whatever */ } }; to force the behavior to something else. He'd just need to make sure that specialization was included before boost::detail::throw_ was instantiated. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTi=1J3+hD0Oh3Le+6-jfnwDLYpTn_A7a6x=oZFnz@mail.gmail.com...
... at worst they'd be mad that you've used Boost (that's common in games, for example.)
Shall we disregard all those cases (of Boost rejection) as irrational rants (as admittedly they often are, be it of the 'corporate policy' type or of the Linus Torvalds type) or shall it be admitted that after all, sometimes, they actually are based on real objections (that Boost, or parts of it, made some not-so-happy efficiency compromising choices)...? -- "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:AANLkTi=1J3+hD0Oh3Le+6-jfnwDLYpTn_A7a6x=oZFnz@mail.gmail.com...
... at worst they'd be mad that you've used Boost (that's common in games, for example.)
Shall we disregard all those cases (of Boost rejection) as irrational rants (as admittedly they often are, be it of the 'corporate policy' type or of the Linus Torvalds type) or shall it be admitted that after all, sometimes, they actually are based on real objections (that Boost, or parts of it, made some not-so-happy efficiency compromising choices)...?
You can't talk about Boost efficiency in general. As difficult as it is to pull apart, Boost contains individual components. Are we talking about the efficiency of Boost Function then? I'm sure if someone manages to speed it up, many people on this mailing list (not to mention the folks who are implementing std::function) would be very interested to see how it can be done. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

At Tue, 19 Oct 2010 01:06:00 -0700, Emil Dotchevski wrote:
On Tue, Oct 19, 2010 at 12:34 AM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTi=1J3+hD0Oh3Le+6-jfnwDLYpTn_A7a6x=oZFnz@mail.gmail.com...
... at worst they'd be mad that you've used Boost (that's common in games, for example.)
Shall we disregard all those cases (of Boost rejection) as irrational rants (as admittedly they often are, be it of the 'corporate policy' type or of the Linus Torvalds type) or shall it be admitted that after all, sometimes, they actually are based on real objections (that Boost, or parts of it, made some not-so-happy efficiency compromising choices)...?
You can't talk about Boost efficiency in general. As difficult as it is to pull apart, Boost contains individual components. Are we talking about the efficiency of Boost Function then? I'm sure if someone manages to speed it up, many people on this mailing list (not to mention the folks who are implementing std::function) would be very interested to see how it can be done.
I think we already know one way: we can easily get rid of the separate empty() check by making sure empty boost::functions all invoke a function that throws bad_function_call. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Tue, Oct 19, 2010 at 4:56 AM, David Abrahams <dave@boostpro.com> wrote:
At Tue, 19 Oct 2010 01:06:00 -0700, Emil Dotchevski wrote:
On Tue, Oct 19, 2010 at 12:34 AM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTi=1J3+hD0Oh3Le+6-jfnwDLYpTn_A7a6x=oZFnz@mail.gmail.com...
... at worst they'd be mad that you've used Boost (that's common in games, for example.)
Shall we disregard all those cases (of Boost rejection) as irrational rants (as admittedly they often are, be it of the 'corporate policy' type or of the Linus Torvalds type) or shall it be admitted that after all, sometimes, they actually are based on real objections (that Boost, or parts of it, made some not-so-happy efficiency compromising choices)...?
You can't talk about Boost efficiency in general. As difficult as it is to pull apart, Boost contains individual components. Are we talking about the efficiency of Boost Function then? I'm sure if someone manages to speed it up, many people on this mailing list (not to mention the folks who are implementing std::function) would be very interested to see how it can be done.
I think we already know one way: we can easily get rid of the separate empty() check by making sure empty boost::functions all invoke a function that throws bad_function_call.
After taking a closer look at this idea, I don't think it is possible to do this without either changing boost::function's semantics or incurring other runtime expenses. First of all, boost::function can be in an empty state for two reasons: either it has not been assigned a target function or there has been a problem with the internal target management system. Both of these conditions are tested simultaneously by the current empty check in operator(). If we get rid of the empty check, we will no longer be checking that the target management system is in working order and able to dispatch function calls (or more specifically, that boost::function's internal vtable pointer is non-null). If the target management system is not in an usable state, then we cannot dispatch a default "empty" function that throws bad_function_call. So, if we get rid of the current empty check but retain the current target management system, we open the possibility that boost::function could be in an empty state but would not throw when invoked, which would be a change in semantics. Alternatively, we could rewrite the target management mechanisms to ensure that boost::function always has a usable vtable object. This implies providing a defualt "empty" vtable, which boost::function's vtable pointer could refer to when in an empty state, so that the pointer is always non-null. There would need to be a different "empty" vtable each time boost::function is instantiated with a different call signature, so that the "empty" vtable can be used seamlessly by operator() for any call signature. These "empty" vtable objects could not be allocated on demand, since they would need to be available to boost::function even in the event of heap allocation failures. So, adding "empty" vtable objects would increase the space requirements of boost::function; each template instantiation would need two corresponding vtable objects, one for actual targets and one as a fallback that throws bad_function_call. (The "empty" vtable objects could be stored statically, but static storage is also a very precious resource on many platforms.) Not all users would appreciate this trade-off; i.e. an increase in the space overhead for a small decrease in time overhead (with compiler optimization the time savings are minuscule, in my experience). I've been studying boost::function's implementation for a while, but perhaps I've missed something. Does anyone have any other insights? Daniel Walker

At Wed, 20 Oct 2010 16:51:50 -0400, Daniel Walker wrote:
First of all, boost::function can be in an empty state for two reasons: either it has not been assigned a target function or there has been a problem with the internal target management system.
What kind of problem? Can you point to code that shows such a problem being detected? Or are you merely saying, "somebody invoked UB somewhere and it nulled out the pointer?" We don't need to support the latter. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Wed, Oct 20, 2010 at 6:04 PM, David Abrahams <dave@boostpro.com> wrote:
At Wed, 20 Oct 2010 16:51:50 -0400, Daniel Walker wrote:
First of all, boost::function can be in an empty state for two reasons: either it has not been assigned a target function or there has been a problem with the internal target management system.
What kind of problem? Can you point to code that shows such a problem being detected? Or are you merely saying, "somebody invoked UB somewhere and it nulled out the pointer?" We don't need to support the latter.
boost::function clones target function objects. So, there could be a failure allocating and/or copy-constructing the target. When this happens, vtable is set to null. You can see an example in operator= on line 783 of function_template.hpp. There may be other reasons that I'm not aware of which could lead to vtable being null. In principle, there is nothing in the current system guaranteeing that vtable is non-null at any arbitrary point in time. Daniel Walker

At Wed, 20 Oct 2010 18:36:01 -0400, Daniel Walker wrote:
On Wed, Oct 20, 2010 at 6:04 PM, David Abrahams <dave@boostpro.com> wrote:
At Wed, 20 Oct 2010 16:51:50 -0400, Daniel Walker wrote:
First of all, boost::function can be in an empty state for two reasons: either it has not been assigned a target function or there has been a problem with the internal target management system.
What kind of problem? Can you point to code that shows such a problem being detected? Or are you merely saying, "somebody invoked UB somewhere and it nulled out the pointer?" We don't need to support the latter.
boost::function clones target function objects. So, there could be a failure allocating and/or copy-constructing the target. When this happens, vtable is set to null. You can see an example in operator= on line 783 of function_template.hpp. There may be other reasons that I'm not aware of which could lead to vtable being null. In principle, there is nothing in the current system guaranteeing that vtable is non-null at any arbitrary point in time.
Of course that happens; it's not a problem. Instead of setting the vtable to null it would be set to point to the empty-state function. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Wed, Oct 20, 2010 at 9:41 PM, David Abrahams <dave@boostpro.com> wrote:
At Wed, 20 Oct 2010 18:36:01 -0400, Daniel Walker wrote:
On Wed, Oct 20, 2010 at 6:04 PM, David Abrahams <dave@boostpro.com> wrote:
At Wed, 20 Oct 2010 16:51:50 -0400, Daniel Walker wrote:
First of all, boost::function can be in an empty state for two reasons: either it has not been assigned a target function or there has been a problem with the internal target management system.
What kind of problem? Can you point to code that shows such a problem being detected? Or are you merely saying, "somebody invoked UB somewhere and it nulled out the pointer?" We don't need to support the latter.
boost::function clones target function objects. So, there could be a failure allocating and/or copy-constructing the target. When this happens, vtable is set to null. You can see an example in operator= on line 783 of function_template.hpp. There may be other reasons that I'm not aware of which could lead to vtable being null. In principle, there is nothing in the current system guaranteeing that vtable is non-null at any arbitrary point in time.
Of course that happens; it's not a problem. Instead of setting the vtable to null it would be set to point to the empty-state function.
Right, I agree. In order to ensure that vtable is not null, everywhere that boost::function currently sets vtable to null, instead, it needs to set vtable to an object that can invoke an empty-state function. Daniel Walker

On Wed, Oct 20, 2010 at 1:51 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Tue, Oct 19, 2010 at 4:56 AM, David Abrahams <dave@boostpro.com> wrote:
At Tue, 19 Oct 2010 01:06:00 -0700, Emil Dotchevski wrote:
On Tue, Oct 19, 2010 at 12:34 AM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTi=1J3+hD0Oh3Le+6-jfnwDLYpTn_A7a6x=oZFnz@mail.gmail.com...
... at worst they'd be mad that you've used Boost (that's common in games, for example.)
Shall we disregard all those cases (of Boost rejection) as irrational rants (as admittedly they often are, be it of the 'corporate policy' type or of the Linus Torvalds type) or shall it be admitted that after all, sometimes, they actually are based on real objections (that Boost, or parts of it, made some not-so-happy efficiency compromising choices)...?
You can't talk about Boost efficiency in general. As difficult as it is to pull apart, Boost contains individual components. Are we talking about the efficiency of Boost Function then? I'm sure if someone manages to speed it up, many people on this mailing list (not to mention the folks who are implementing std::function) would be very interested to see how it can be done.
I think we already know one way: we can easily get rid of the separate empty() check by making sure empty boost::functions all invoke a function that throws bad_function_call.
After taking a closer look at this idea, I don't think it is possible to do this without either changing boost::function's semantics or incurring other runtime expenses.
First of all, boost::function can be in an empty state for two reasons: either it has not been assigned a target function or there has been a problem with the internal target management system. Both of these conditions are tested simultaneously by the current empty check in operator(). If we get rid of the empty check, we will no longer be checking that the target management system is in working order and able to dispatch function calls (or more specifically, that boost::function's internal vtable pointer is non-null). If the target management system is not in an usable state, then we cannot dispatch a default "empty" function that throws bad_function_call. So, if we get rid of the current empty check but retain the current target management system, we open the possibility that boost::function could be in an empty state but would not throw when invoked, which would be a change in semantics.
The latter "state" isn't a real state; it only exists if there's a bug in boost::function, and we don't design around bugs.
Alternatively, we could rewrite the target management mechanisms to ensure that boost::function always has a usable vtable object. This implies providing a defualt "empty" vtable, which boost::function's vtable pointer could refer to when in an empty state, so that the pointer is always non-null.
Yes, that's the implementation technique that has been discussed a number of times.
There would need to be a different "empty" vtable each time boost::function is instantiated with a different call signature, so that the "empty" vtable can be used seamlessly by operator() for any call signature.
One per boost::function signature, yes.
These "empty" vtable objects could not be allocated on demand, since they would need to be available to boost::function even in the event of heap allocation failures.
They would go into the data segment, as the current vtables do.
So, adding "empty" vtable objects would increase the space requirements of boost::function; each template instantiation would need two corresponding vtable objects, one for actual targets and one as a fallback that throws bad_function_call. (The "empty" vtable objects could be stored statically, but static storage is also a very precious resource on many platforms.) Not all users would appreciate this trade-off; i.e. an increase in the space overhead for a small decrease in time overhead (with compiler optimization the time savings are minuscule, in my experience).
Without quantifying the trade-off, we don't know which way is better. In any case, this issue is fairly easy to settle; it just takes effort. Someone implements this alternative scheme and determines the cost/benefit in space and time, and with any luck the choice is obvious. - Doug

On Thu, Oct 21, 2010 at 2:25 AM, Doug Gregor <doug.gregor@gmail.com> wrote:
On Wed, Oct 20, 2010 at 1:51 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Tue, Oct 19, 2010 at 4:56 AM, David Abrahams <dave@boostpro.com> wrote:
At Tue, 19 Oct 2010 01:06:00 -0700, Emil Dotchevski wrote:
On Tue, Oct 19, 2010 at 12:34 AM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTi=1J3+hD0Oh3Le+6-jfnwDLYpTn_A7a6x=oZFnz@mail.gmail.com...
... at worst they'd be mad that you've used Boost (that's common in games, for example.)
Shall we disregard all those cases (of Boost rejection) as irrational rants (as admittedly they often are, be it of the 'corporate policy' type or of the Linus Torvalds type) or shall it be admitted that after all, sometimes, they actually are based on real objections (that Boost, or parts of it, made some not-so-happy efficiency compromising choices)...?
You can't talk about Boost efficiency in general. As difficult as it is to pull apart, Boost contains individual components. Are we talking about the efficiency of Boost Function then? I'm sure if someone manages to speed it up, many people on this mailing list (not to mention the folks who are implementing std::function) would be very interested to see how it can be done.
I think we already know one way: we can easily get rid of the separate empty() check by making sure empty boost::functions all invoke a function that throws bad_function_call.
After taking a closer look at this idea, I don't think it is possible to do this without either changing boost::function's semantics or incurring other runtime expenses.
First of all, boost::function can be in an empty state for two reasons: either it has not been assigned a target function or there has been a problem with the internal target management system. Both of these conditions are tested simultaneously by the current empty check in operator(). If we get rid of the empty check, we will no longer be checking that the target management system is in working order and able to dispatch function calls (or more specifically, that boost::function's internal vtable pointer is non-null). If the target management system is not in an usable state, then we cannot dispatch a default "empty" function that throws bad_function_call. So, if we get rid of the current empty check but retain the current target management system, we open the possibility that boost::function could be in an empty state but would not throw when invoked, which would be a change in semantics.
The latter "state" isn't a real state; it only exists if there's a bug in boost::function, and we don't design around bugs.
Right. I don't mean the management system has a bug, I mean that it has encountered a problem, for example, cloning the target. So, boost::function could be empty because it has never been assigned a target or because the most recent attempt to assign a target failed... or because it was cleared by the user calling clear(). Are those all of the scenarios that can lead to an empty boost::function?
Alternatively, we could rewrite the target management mechanisms to ensure that boost::function always has a usable vtable object. This implies providing a defualt "empty" vtable, which boost::function's vtable pointer could refer to when in an empty state, so that the pointer is always non-null.
Yes, that's the implementation technique that has been discussed a number of times.
Ok, good. I missed out on a lot of those old discussions, so I'm just now catching up... or trying to, at least. :)
There would need to be a different "empty" vtable each time boost::function is instantiated with a different call signature, so that the "empty" vtable can be used seamlessly by operator() for any call signature.
One per boost::function signature, yes.
These "empty" vtable objects could not be allocated on demand, since they would need to be available to boost::function even in the event of heap allocation failures.
They would go into the data segment, as the current vtables do.
So, adding "empty" vtable objects would increase the space requirements of boost::function; each template instantiation would need two corresponding vtable objects, one for actual targets and one as a fallback that throws bad_function_call. (The "empty" vtable objects could be stored statically, but static storage is also a very precious resource on many platforms.) Not all users would appreciate this trade-off; i.e. an increase in the space overhead for a small decrease in time overhead (with compiler optimization the time savings are minuscule, in my experience).
Without quantifying the trade-off, we don't know which way is better.
Do you have any suggestion for how to quantify this? I've run some simple benchmarks, but in optimized object code the time overhead of boost::function is so small it's hard to measure. The increase in size of the data segment is more straight forward, but don't we already know it will double? Instead of one vtable object per signature, there would be two per signature, right?
In any case, this issue is fairly easy to settle; it just takes effort. Someone implements this alternative scheme and determines the cost/benefit in space and time, and with any luck the choice is obvious.
OK, I'm going to spend some more time on this, try to give a working implementation, and give a report back. Thanks for the help! Daniel Walker

On 10/21/2010 6:05 PM, Daniel Walker wrote:
On Thu, Oct 21, 2010 at 2:25 AM, Doug Gregor<doug.gregor@gmail.com> wrote:
On Wed, Oct 20, 2010 at 1:51 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Tue, Oct 19, 2010 at 4:56 AM, David Abrahams<dave@boostpro.com> wrote:
At Tue, 19 Oct 2010 01:06:00 -0700, Emil Dotchevski wrote:
On Tue, Oct 19, 2010 at 12:34 AM, Domagoj Saric<dsaritz@gmail.com> wrote:
"Emil Dotchevski"<emil@revergestudios.com> wrote in message news:AANLkTi=1J3+hD0Oh3Le+6-jfnwDLYpTn_A7a6x=oZFnz@mail.gmail.com...
> ... at worst they'd be mad that you've used > Boost (that's common in games, for example.)
Shall we disregard all those cases (of Boost rejection) as irrational rants (as admittedly they often are, be it of the 'corporate policy' type or of the Linus Torvalds type) or shall it be admitted that after all, sometimes, they actually are based on real objections (that Boost, or parts of it, made some not-so-happy efficiency compromising choices)...?
You can't talk about Boost efficiency in general. As difficult as it is to pull apart, Boost contains individual components. Are we talking about the efficiency of Boost Function then? I'm sure if someone manages to speed it up, many people on this mailing list (not to mention the folks who are implementing std::function) would be very interested to see how it can be done.
I think we already know one way: we can easily get rid of the separate empty() check by making sure empty boost::functions all invoke a function that throws bad_function_call.
After taking a closer look at this idea, I don't think it is possible to do this without either changing boost::function's semantics or incurring other runtime expenses.
First of all, boost::function can be in an empty state for two reasons: either it has not been assigned a target function or there has been a problem with the internal target management system. Both of these conditions are tested simultaneously by the current empty check in operator(). If we get rid of the empty check, we will no longer be checking that the target management system is in working order and able to dispatch function calls (or more specifically, that boost::function's internal vtable pointer is non-null). If the target management system is not in an usable state, then we cannot dispatch a default "empty" function that throws bad_function_call. So, if we get rid of the current empty check but retain the current target management system, we open the possibility that boost::function could be in an empty state but would not throw when invoked, which would be a change in semantics.
The latter "state" isn't a real state; it only exists if there's a bug in boost::function, and we don't design around bugs.
Right. I don't mean the management system has a bug, I mean that it has encountered a problem, for example, cloning the target. So, boost::function could be empty because it has never been assigned a target or because the most recent attempt to assign a target failed... or because it was cleared by the user calling clear(). Are those all of the scenarios that can lead to an empty boost::function?
I don't mean to question the design of boost::function but wouldn't the inability of cloning a target, or assign a target, be a problem which should lead to an exception being thrown ? I would assume that boost::function not having a target would normally only occur if no target had been set or if the user removed a target which had been set.

On Thu, Oct 21, 2010 at 6:13 PM, Edward Diener <eldiener@tropicsoft.com> wrote:
On 10/21/2010 6:05 PM, Daniel Walker wrote:
On Thu, Oct 21, 2010 at 2:25 AM, Doug Gregor<doug.gregor@gmail.com> wrote:
On Wed, Oct 20, 2010 at 1:51 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Tue, Oct 19, 2010 at 4:56 AM, David Abrahams<dave@boostpro.com> wrote:
At Tue, 19 Oct 2010 01:06:00 -0700, Emil Dotchevski wrote:
On Tue, Oct 19, 2010 at 12:34 AM, Domagoj Saric<dsaritz@gmail.com> wrote: > > "Emil Dotchevski"<emil@revergestudios.com> wrote in message > news:AANLkTi=1J3+hD0Oh3Le+6-jfnwDLYpTn_A7a6x=oZFnz@mail.gmail.com... > >> ... at worst they'd be mad that you've used >> Boost (that's common in games, for example.) > > Shall we disregard all those cases (of Boost rejection) as irrational > rants > (as admittedly they often are, be it of the 'corporate policy' type > or of > the Linus Torvalds type) or shall it be admitted that after all, > sometimes, > they actually are based on real objections (that Boost, or parts of > it, made > some not-so-happy efficiency compromising choices)...?
You can't talk about Boost efficiency in general. As difficult as it is to pull apart, Boost contains individual components. Are we talking about the efficiency of Boost Function then? I'm sure if someone manages to speed it up, many people on this mailing list (not to mention the folks who are implementing std::function) would be very interested to see how it can be done.
I think we already know one way: we can easily get rid of the separate empty() check by making sure empty boost::functions all invoke a function that throws bad_function_call.
After taking a closer look at this idea, I don't think it is possible to do this without either changing boost::function's semantics or incurring other runtime expenses.
First of all, boost::function can be in an empty state for two reasons: either it has not been assigned a target function or there has been a problem with the internal target management system. Both of these conditions are tested simultaneously by the current empty check in operator(). If we get rid of the empty check, we will no longer be checking that the target management system is in working order and able to dispatch function calls (or more specifically, that boost::function's internal vtable pointer is non-null). If the target management system is not in an usable state, then we cannot dispatch a default "empty" function that throws bad_function_call. So, if we get rid of the current empty check but retain the current target management system, we open the possibility that boost::function could be in an empty state but would not throw when invoked, which would be a change in semantics.
The latter "state" isn't a real state; it only exists if there's a bug in boost::function, and we don't design around bugs.
Right. I don't mean the management system has a bug, I mean that it has encountered a problem, for example, cloning the target. So, boost::function could be empty because it has never been assigned a target or because the most recent attempt to assign a target failed... or because it was cleared by the user calling clear(). Are those all of the scenarios that can lead to an empty boost::function?
I don't mean to question the design of boost::function but wouldn't the inability of cloning a target, or assign a target, be a problem which should lead to an exception being thrown ?
Right, but suppose boost::function was instantiated outside of the try block where the assignment fails. Then after the exception is thrown and handled, the boost::function object could still be used. But actually, I just noticed that, even though the portable function wrappers are empty after an assignment failure, boost::function is not actually cleared. So, in fact, a failed assignment is NOT a scenario that leads to an empty state, as I first thought. This is probably an oversight/bug in the portable wrappers, right?
I would assume that boost::function not having a target would normally only occur if no target had been set or if the user removed a target which had been set.
Right, and indeed, this appears to be the case... unless there's some other scenario we overlooked... Daniel Walker

On Thu, Oct 21, 2010 at 7:05 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Thu, Oct 21, 2010 at 6:13 PM, Edward Diener <eldiener@tropicsoft.com> wrote:
On 10/21/2010 6:05 PM, Daniel Walker wrote:
Right. I don't mean the management system has a bug, I mean that it has encountered a problem, for example, cloning the target. So, boost::function could be empty because it has never been assigned a target or because the most recent attempt to assign a target failed... or because it was cleared by the user calling clear(). Are those all of the scenarios that can lead to an empty boost::function?
I don't mean to question the design of boost::function but wouldn't the inability of cloning a target, or assign a target, be a problem which should lead to an exception being thrown ?
Right, but suppose boost::function was instantiated outside of the try block where the assignment fails. Then after the exception is thrown and handled, the boost::function object could still be used.
But actually, I just noticed that, even though the portable function wrappers are empty after an assignment failure, boost::function is not actually cleared. So, in fact, a failed assignment is NOT a scenario that leads to an empty state, as I first thought. This is probably an oversight/bug in the portable wrappers, right?
I would assume that boost::function not having a target would normally only occur if no target had been set or if the user removed a target which had been set.
Right, and indeed, this appears to be the case... unless there's some other scenario we overlooked...
Oops. Sorry, I spoke too soon. In fact, it IS currently possible for a boost::function object to become empty due to a failed assignment. It happens because the small object manager clones the target during a call to swap(). If there is an exception during the allocation, boost::function handles it, sets itself to empty and rethrows. Here's an example that demonstrates the behavior. #include <cassert> #include <iostream> #include <boost/function.hpp> struct S0 { void operator()() {} }; int i = 0; struct S1 { void operator()() {} void* operator new(std::size_t, void*) { // throw on third alloc if(++i == 3) throw std::bad_alloc(); } }; int main() { boost::function<void()> g = S0(); assert(g); // assertion ok, since g is not empty. try { g = S1(); } catch(std::exception& e) { std::cerr << "failed function assignment: " << e.what() << std::endl; } assert(g); // now assert fails, since g is empty. return 0; } Here's a backtrace just before the bad_alloc is thrown. #0 S1::operator new () at function_assignment_test.cpp:15 #1 0x00000001000019e1 in boost::detail::function::functor_manager_common<S1>::manage_small (in_buffer=@0x7fff5fbff298, out_buffer=@0x7fff5fbff378, op=boost::detail::function::move_functor_tag) at function_base.hpp:318 #2 0x0000000100001abf in boost::detail::function::functor_manager<S1>::manager (in_buffer=@0x7fff5fbff298, out_buffer=@0x7fff5fbff378, op=boost::detail::function::move_functor_tag) at function_base.hpp:364 #3 0x0000000100001aeb in boost::detail::function::functor_manager<S1>::manager (in_buffer=@0x7fff5fbff298, out_buffer=@0x7fff5fbff378, op=boost::detail::function::move_functor_tag) at function_base.hpp:412 #4 0x0000000100001b44 in boost::detail::function::functor_manager<S1>::manage (in_buffer=@0x7fff5fbff298, out_buffer=@0x7fff5fbff378, op=boost::detail::function::move_functor_tag) at function_base.hpp:440 #5 0x0000000100001d25 in boost::function0<void>::move_assign (this=0x7fff5fbff370, f=@0x7fff5fbff290) at function_template.hpp:974 #6 0x0000000100001dc7 in boost::function0<void>::swap (this=0x7fff5fbff300, other=@0x7fff5fbff370) at function_template.hpp:848 #7 0x0000000100001e2a in boost::function<void ()()>::operator=<S1> (this=0x7fff5fbff370, f={<No data fields>}) at function_template.hpp:1105 #8 0x0000000100001221 in main () at function_assignment_test.cpp:25 Daniel Walker

On Fri, Oct 22, 2010 at 1:35 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Oops. Sorry, I spoke too soon. In fact, it IS currently possible for a boost::function object to become empty due to a failed assignment. It happens because the small object manager clones the target during a call to swap(). If there is an exception during the allocation, boost::function handles it, sets itself to empty and rethrows. Here's an example that demonstrates the behavior.
One more thing, for those who are interested. To make the example portable, you need to add a destructor to S1. Also, so as not to cause confusion, I should have had operator new actually allocate something. :P So, to reproduce the behavior the following is a complete example that works on msvc 10 and gcc 4.2. #include <cassert> #include <iostream> #include <boost/function.hpp> struct S0 { void operator()() {} }; int i = 0; struct S1 { ~S1() {} void operator()() {} void* operator new(std::size_t, void* p) { // throw on third alloc if(++i == 3) throw std::bad_alloc(); return p = ::new S1(); } }; int main() { boost::function<void()> g = S0(); assert(g); // assertion ok, since g is not empty. try { g = S1(); } catch(std::exception& e) { std::cerr << "failed function assignment: " << e.what() << std::endl; } assert(g); // now assert fails, since g is empty. return 0; } Daniel Walker

On 22 October 2010 14:09, Daniel Walker <daniel.j.walker@gmail.com> wrote:
To make the example portable, you need to add a destructor to S1.
Why?
struct S1 { ~S1() {} void operator()() {} void* operator new(std::size_t, void* p) { // throw on third alloc if(++i == 3) throw std::bad_alloc(); return p = ::new S1(); } }; -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404

On Fri, Oct 22, 2010 at 5:01 PM, Nevin Liber <nevin@eviloverlord.com> wrote:
On 22 October 2010 14:09, Daniel Walker <daniel.j.walker@gmail.com> wrote:
To make the example portable, you need to add a destructor to S1.
Why?
This is to force function_base::has_trivial_copy_and_destroy() to evaluate to false on line 971 of function_template.hpp. (Different compilers handle default destructors differently, so to force the same behavior on all platforms, you need to define a destructor.) The target function object is only cloned if it has a copy-constructor or destructor, since cloning is not necessary when swapping stateless function objects. Good question.
struct S1 { ~S1() {} void operator()() {} void* operator new(std::size_t, void* p) { // throw on third alloc if(++i == 3) throw std::bad_alloc(); return p = ::new S1(); } };
I just realized there is another technical error in my example, though it doesn't affect the behavior being demonstrated. That operator new is an in-place new, of course, so the return should be: return ::operator new (s, p); Thanks! Daniel Walker

On Fri, Oct 22, 2010 at 10:35 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Oops. Sorry, I spoke too soon. In fact, it IS currently possible for a boost::function object to become empty due to a failed assignment. It happens because the small object manager clones the target during a call to swap(). If there is an exception during the allocation, boost::function handles it, sets itself to empty and rethrows.
Unless you can find specific documentation for this behavior (I couldn't), you can't assume that op= will leave the target empty upon failure. AFAIK it provides only basic exception safety, meaning the state of the target is unspecified upon failure except that no memory will leak. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Fri, Oct 22, 2010 at 3:39 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Fri, Oct 22, 2010 at 10:35 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Oops. Sorry, I spoke too soon. In fact, it IS currently possible for a boost::function object to become empty due to a failed assignment. It happens because the small object manager clones the target during a call to swap(). If there is an exception during the allocation, boost::function handles it, sets itself to empty and rethrows.
Unless you can find specific documentation for this behavior (I couldn't), you can't assume that op= will leave the target empty upon failure.
True, but my point is that it is _possible_ for operator= to leave boost::function empty. So if we change how the current implementation of boost::function enters the empty state, we need to take account of this case.
AFAIK it provides only basic exception safety, meaning the state of the target is unspecified upon failure except that no memory will leak.
Changing boost::function's internal vtable from null to a static "empty" vtable will not change the exception safety of any of its member functions. However, it will increase the space overhead in the data segment. Daniel Walker

On 10/22/2010 1:35 PM, Daniel Walker wrote:
On Thu, Oct 21, 2010 at 7:05 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Thu, Oct 21, 2010 at 6:13 PM, Edward Diener<eldiener@tropicsoft.com> wrote:
On 10/21/2010 6:05 PM, Daniel Walker wrote:
Right. I don't mean the management system has a bug, I mean that it has encountered a problem, for example, cloning the target. So, boost::function could be empty because it has never been assigned a target or because the most recent attempt to assign a target failed... or because it was cleared by the user calling clear(). Are those all of the scenarios that can lead to an empty boost::function?
I don't mean to question the design of boost::function but wouldn't the inability of cloning a target, or assign a target, be a problem which should lead to an exception being thrown ?
Right, but suppose boost::function was instantiated outside of the try block where the assignment fails. Then after the exception is thrown and handled, the boost::function object could still be used.
But actually, I just noticed that, even though the portable function wrappers are empty after an assignment failure, boost::function is not actually cleared. So, in fact, a failed assignment is NOT a scenario that leads to an empty state, as I first thought. This is probably an oversight/bug in the portable wrappers, right?
I would assume that boost::function not having a target would normally only occur if no target had been set or if the user removed a target which had been set.
Right, and indeed, this appears to be the case... unless there's some other scenario we overlooked...
Oops. Sorry, I spoke too soon. In fact, it IS currently possible for a boost::function object to become empty due to a failed assignment. It happens because the small object manager clones the target during a call to swap(). If there is an exception during the allocation, boost::function handles it, sets itself to empty and rethrows.
That's understandable. Once an exception is thrown its the end-user's responsibility to deal with the end result. I do not understand why others are upset that invoking boost::function on an empty target should throw an exception. It is equivalent in my mind to calling a function through a function pointer which is null.

"Edward Diener" <eldiener@tropicsoft.com> wrote in message news:i9tsoi$7m2$1@dough.gmane.org...
I do not understand why others are upset that invoking boost::function on an empty target should throw an exception. It is equivalent in my mind to calling a function through a function pointer which is null.
Short recap of some of the problems (with the current implementation) WRT to the throw-on-empty issue: - the way the throwing is implemented is inefficient (both in terms of speed and template code bloat) - the check and throwing may be entirely redundant if the calling code already checks/ensures that it does not call an empty function - there is no way to choose a different on-empty behaviour ... -- "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 Sat, Oct 23, 2010 at 12:01 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Edward Diener" <eldiener@tropicsoft.com> wrote in message news:i9tsoi$7m2$1@dough.gmane.org...
I do not understand why others are upset that invoking boost::function on an empty target should throw an exception. It is equivalent in my mind to calling a function through a function pointer which is null.
Short recap of some of the problems (with the current implementation) WRT to the throw-on-empty issue: - the way the throwing is implemented is inefficient (both in terms of speed and template code bloat) - the check and throwing may be entirely redundant if the calling code already checks/ensures that it does not call an empty function
As pointed out, the check can be removed. We're waiting for someone who cares about the current inefficiency of the check to remove it instead of arguing. :)
- there is no way to choose a different on-empty behaviour
You're missing the point I believe Edward is making. Throwing an exception when an empty function is called is a valid behavior in case the on-empty behavior is undefined (don't call empty functions if you don't want the exception.) Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTik0aePsrXAPPUt8-MnbTT7863bB8_51x+8YfWaL@mail.gmail.com...
As pointed out, the check can be removed. We're waiting for someone who cares about the current inefficiency of the check to remove it instead of arguing. :)
I am sorry but I'm really starting to doubt someone's sanity here.... You keep saying things to the effect of the above statement while I keep replying to you that I care and already have (as well as others), long ago, 'removed the check' as well as made many other improvements (along with links to code, tests and discussions)....which you again ignore....and so we go....'running in circles'....ad nauseam... Am I the only one seeing my own particular posts on this subject on this list?
- there is no way to choose a different on-empty behaviour
You're missing the point I believe Edward is making. Throwing an exception when an empty function is called is a valid behavior in case the on-empty behavior is undefined (don't call empty functions if you don't want the exception.)
More of the straw man arguments...it is quite obvious that just about anyone complaining about the on-empty behaviour of boost::function simply: - does not care about the 'academic' meaning of 'undefined behaviour' - does not care about the 'academic' meaning of 'behaviour' per se but about behaviour in the context of the overhead and dependency implications/requirements of that particular behaviour - never asked for the removal/configurability of the hardcoded throw-on-empty policy with the explicit goal to specifically get undefined-behaviour instead (this would obviously be oxymoronic) >but< to remove it to get rid of the associated >overhead< and >runtime dependencies< (simply unavailable in some environments), in turn >accepting< to get undefined behaviour >through/because of a call through a null function pointer< if they fail to obey by their promise not call an empty boost::function... IOW, the fact that in theory, while not in practice, 'undefined behaviour' may mean 'anything', thus also the same throw-on-empty behaviour that we have in status quo, has exactly zero relevance to the core point in question because, >even in theory<, 'undefined behaviour' does not imply any sort of implementation or 'physical code' or 'overhead' or 'dependency' and >that< is the core point in question, making your 'academic' argument (that again, I'm sorry, you seem to be repeating ad nauseam) a text book example of a straw man argument... (Because the status quo implementation does have unwanted overheads and dependencies while the proposed ones do not/offer some improvement, and, again, the fact that you repeatedly try to prove that theory says that there is no difference, and hence gives no justification for the claim, is fully irrelevant because you sidestep and distort the original claims and requests in order to get to your point...the only remaining question is why?) ps. Edward was asking "why others are upset that invoking boost::function on an empty target should throw an exception", whether or not this implies he meant specifically and solely on the issue of behaviour (separated from the context of overhead and dependencies), which is the issue of the above described straw man argument, is irrelevant...because even if he did it would be 'valid' of me then to point him to the real merit and context of the discussion.... -- "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 Sat, Oct 23, 2010 at 2:30 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTik0aePsrXAPPUt8-MnbTT7863bB8_51x+8YfWaL@mail.gmail.com...
As pointed out, the check can be removed. We're waiting for someone who cares about the current inefficiency of the check to remove it instead of arguing. :)
I am sorry but I'm really starting to doubt someone's sanity here.... You keep saying things to the effect of the above statement while I keep replying to you that I care and already have (as well as others), long ago, 'removed the check' as well as made many other improvements (along with links to code, tests and discussions)....which you again ignore....and so we go....'running in circles'....ad nauseam... Am I the only one seeing my own particular posts on this subject on this list?
The check and the associated overhead can be easily removed in boost::function. I have not seen anyone post a diff that removes the check in boost::function. Maybe I missed it.
- there is no way to choose a different on-empty behaviour
You're missing the point I believe Edward is making. Throwing an exception when an empty function is called is a valid behavior in case the on-empty behavior is undefined (don't call empty functions if you don't want the exception.)
- never asked for the removal/configurability of the hardcoded throw-on-empty policy with the explicit goal to specifically get undefined-behaviour instead (this would obviously be oxymoronic) >but< to remove it to get rid of the associated >overhead< and >runtime dependencies<
The link dependency (in BOOST_NO_EXCEPTIONS builds) on boost::throw_exception exists specifically to enable using Boost when exceptions are disabled. If that system is flawed, let's talk about improving it (note that its semantics are a perfect match for the requested empty-function-call semantics.) That said, anyone can implement a new policy-based function library, specify its interface (write documentation) and request a Boost review. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTimASWRoLipBTEby+peHY4zd4zguRu4PW85UeQpv@mail.gmail.com...
The check and the associated overhead can be easily removed in boost::function. I have not seen anyone post a diff that removes the check in boost::function. Maybe I missed it.
Oh, I see, a technicality issue...sandbox and vault code are not good enough to discuss... -- "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 10/23/2010 5:30 PM, Domagoj Saric wrote:
"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTik0aePsrXAPPUt8-MnbTT7863bB8_51x+8YfWaL@mail.gmail.com...
As pointed out, the check can be removed. We're waiting for someone who cares about the current inefficiency of the check to remove it instead of arguing. :)
I am sorry but I'm really starting to doubt someone's sanity here.... You keep saying things to the effect of the above statement while I keep replying to you that I care and already have (as well as others), long ago, 'removed the check' as well as made many other improvements (along with links to code, tests and discussions)....which you again ignore....and so we go....'running in circles'....ad nauseam... Am I the only one seeing my own particular posts on this subject on this list?
- there is no way to choose a different on-empty behaviour
You're missing the point I believe Edward is making. Throwing an exception when an empty function is called is a valid behavior in case the on-empty behavior is undefined (don't call empty functions if you don't want the exception.)
accepting< to get undefined behaviour >through/because of a call
More of the straw man arguments...it is quite obvious that just about anyone complaining about the on-empty behaviour of boost::function simply: - does not care about the 'academic' meaning of 'undefined behaviour' - does not care about the 'academic' meaning of 'behaviour' per se but about behaviour in the context of the overhead and dependency implications/requirements of that particular behaviour - never asked for the removal/configurability of the hardcoded throw-on-empty policy with the explicit goal to specifically get undefined-behaviour instead (this would obviously be oxymoronic) >but< to remove it to get rid of the associated >overhead< and >runtime dependencies< (simply unavailable in some environments), in turn through a null function pointer< if they fail to obey by their promise not call an empty boost::function...
IOW, the fact that in theory, while not in practice, 'undefined behaviour' may mean 'anything', thus also the same throw-on-empty behaviour that we have in status quo, has exactly zero relevance to the core point in question because, >even in theory<, 'undefined behaviour' does not imply any sort of implementation or 'physical code' or 'overhead' or 'dependency' and >that< is the core point in question, making your 'academic' argument (that again, I'm sorry, you seem to be repeating ad nauseam) a text book example of a straw man argument... (Because the status quo implementation does have unwanted overheads and dependencies while the proposed ones do not/offer some improvement, and, again, the fact that you repeatedly try to prove that theory says that there is no difference, and hence gives no justification for the claim, is fully irrelevant because you sidestep and distort the original claims and requests in order to get to your point...the only remaining question is why?)
ps. Edward was asking "why others are upset that invoking boost::function on an empty target should throw an exception", whether or not this implies he meant specifically and solely on the issue of behaviour (separated from the context of overhead and dependencies), which is the issue of the above described straw man argument, is irrelevant...because even if he did it would be 'valid' of me then to point him to the real merit and context of the discussion....
I meant simply what I said. Please explain to me why boost::function throwing an exception when invoked on an empty target is objectionable to you. If I have misunderstand to what you are objecting I apologize, but it seems to me that you find this behavior incorrect somehow. In reading the documentation it clearly states: "boost::bad_function_call — An exception type thrown when an instance of a function object is empty when invoked."

On Sun, Oct 24, 2010 at 1:17 AM, Edward Diener <eldiener@tropicsoft.com> wrote:
On 10/23/2010 5:30 PM, Domagoj Saric wrote:
[snip]
I meant simply what I said. Please explain to me why boost::function throwing an exception when invoked on an empty target is objectionable to you. If I have misunderstand to what you are objecting I apologize, but it seems to me that you find this behavior incorrect somehow.
The question is not directed at me, but I feel compelled to answer it. I do find it incorrect to throw when invoked on an empty target because I feel that this should be a contract for operator() and contracts should be checked with asserts, which make it easier for debugging and have no overhead (RTTI or otherwise) when compiled with NDEBUG.
In reading the documentation it clearly states:
"boost::bad_function_call — An exception type thrown when an instance of a function object is empty when invoked."
Unfortunately, breaking changes are very complicated to get in. Regards, -- Felipe Magno de Almeida

"Edward Diener" <eldiener@tropicsoft.com> wrote in message news:ia08ha$eea$1@dough.gmane.org...
I meant simply what I said. Please explain to me why boost::function throwing an exception when invoked on an empty target is objectionable to you. If I have misunderstand to what you are objecting I apologize, but it seems to me that you find this behavior incorrect somehow.
I thought I did in my first reply to you as well as the next one to Emil Dotchevski... To restate only the general picture as short as possible, the problem is not in the 'documented behaviour' as such/in itself but in the context of all of the implications of that/such behaviour...Just as the core 'objection(s)' are not concentrated on some idea of behaviour but about the specifics of the current implementation... -- "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

"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTikXL0i5Z+NoO2a3TiB8q2RmTk4oHJ1kzOyR-7vE@mail.gmail.com...
Do you have any suggestion for how to quantify this? I've run some simple benchmarks, but in optimized object code the time overhead of boost::function is so small it's hard to measure.
Those benchmarks are obviously lacking...I've given you examples that show that the various overheads of the current implementation are quite measurable...
The increase in size of the data segment is more straight forward, but don't we already know it will double? Instead of one vtable object per signature, there would be two per signature, right?
No, as explained in the previous post, the overhead is either zero, or one extra vtable per binary or one extra vtable per b.function signature... -- "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 Sat, Oct 23, 2010 at 3:00 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTikXL0i5Z+NoO2a3TiB8q2RmTk4oHJ1kzOyR-7vE@mail.gmail.com...
Do you have any suggestion for how to quantify this? I've run some simple benchmarks, but in optimized object code the time overhead of boost::function is so small it's hard to measure.
Those benchmarks are obviously lacking...I've given you examples that show that the various overheads of the current implementation are quite measurable...
Sorry, I must have missed your examples. Here's a simple benchmark that we could use: template<class T> double benchmark(T f, int n) { assert(f); boost::timer t; for(int i = 0; i < n; ++i) f(i); return t.elapsed(); } int echo(int x) { return x; } int main() { int n = INT_MAX; boost::function<int(int)> f = &echo; double baseline = benchmark(&echo, n); double t = benchmark(f, n); assert(baseline < t); std::cout << "boost::function overhead = " << (t - baseline) / n << " seconds" << std::endl; return 0; } On my machine, this measures the overhead of boost::function as 2 nanoseconds, though, obviously, this is a statistical inference and quantities of time that small are hard to measure. Does anyone have other suggestions for how to benchmark boost::function? Daniel Walker

On Mon, Oct 25, 2010 at 1:54 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Sat, Oct 23, 2010 at 3:00 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTikXL0i5Z+NoO2a3TiB8q2RmTk4oHJ1kzOyR-7vE@mail.gmail.com...
Do you have any suggestion for how to quantify this? I've run some simple benchmarks, but in optimized object code the time overhead of boost::function is so small it's hard to measure.
Those benchmarks are obviously lacking...I've given you examples that show that the various overheads of the current implementation are quite measurable...
Sorry, I must have missed your examples. Here's a simple benchmark that we could use:
template<class T> double benchmark(T f, int n) { assert(f); boost::timer t; for(int i = 0; i < n; ++i) f(i); return t.elapsed(); }
int echo(int x) { return x; }
int main() { int n = INT_MAX; boost::function<int(int)> f = &echo;
double baseline = benchmark(&echo, n); double t = benchmark(f, n); assert(baseline < t);
std::cout << "boost::function overhead = " << (t - baseline) / n << " seconds" << std::endl; return 0; }
On my machine, this measures the overhead of boost::function as 2 nanoseconds, though, obviously, this is a statistical inference and quantities of time that small are hard to measure.
I've found that such benchmarks, while able to produce long mailing list discussions, don't have much practical value. Do you have a performance problem with the current boost::function? An actual program or application which would run noticeably faster with the 2 nanoseconds per call speedup? Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTi=XyK9WhaKJO8K8y8AAj70WawJU1TqFHgQd35Tk@mail.gmail.com...
Sorry, I must have missed your examples.
e.g. http://lists.boost.org/Archives/boost/2010/01/160908.php
Here's a simple benchmark that we could use: ...snip....
As already explained, such test consisting of simple straightforward for loop are no good as a capable compiler is able to hoist the if check outside of the loop (if the overhead of the 'if' is the only thing we are considering)... -- "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 Sat, Oct 30, 2010 at 1:25 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTi=XyK9WhaKJO8K8y8AAj70WawJU1TqFHgQd35Tk@mail.gmail.com...
Sorry, I must have missed your examples.
e.g. http://lists.boost.org/Archives/boost/2010/01/160908.php
Thanks. I added a tarball, signal_benchmark.tar.bz2, with a jamfile and source code so that anyone who's interested can easily reproduce this benchmark. The benchmark measures the impact of the static empty scheme on the time per call of boost::signals2::signal using the code Domagoj linked to. Thanks to Christophe Prud'homme for the original benchmark! Here are the results I got, again, using the build of g++ 4.2 provided by my manufacturer. Data (Release): | function | function (static empty) time/call | 3.54e-07s | 3.51e-07s space/type | 64B | 80B Data (Debug): | function | function (static empty) time/call | 2.05e-06s | 2.04e-06s space/type | 64B | 80B You can see that removing the empty check from boost::function yields about a 1% improvement in time per call to boost::signal. The increased space per type overhead is the same as before: 16B. So, basically, in the use-case measured by this benchmark the time overhead of boost::function is dwarfed by the combined costs of boost::signal and the target function, and so using the static empty scheme does not yield much benefit. Again, the actual performance will depend on you compiler's optimization, so some users may receive more benefit than others. This is why I think we should give users the chance to test the two schemes in their own applications and choose the one that works best for them. Daniel Walker

On 11/02/2010 02:50 PM, Daniel Walker wrote: [...]
Here are the results I got, again, using the build of g++ 4.2 provided by my manufacturer.
Data (Release): | function | function (static empty) time/call | 3.54e-07s | 3.51e-07s space/type | 64B | 80B
Data (Debug): | function | function (static empty) time/call | 2.05e-06s | 2.04e-06s space/type | 64B | 80B
You can see that removing the empty check from boost::function yields about a 1% improvement in time per call to boost::signal. The increased space per type overhead is the same as before: 16B. [...]
[Butting in after only vaguely following this thread...] Would it also be appropriate to measure the "space/call", in addition to "time/call" and "space/type"? Or is there no difference, or had this been addressed already? - Jeff

On Tue, Nov 2, 2010 at 7:20 PM, Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> wrote:
On 11/02/2010 02:50 PM, Daniel Walker wrote: [...]
Here are the results I got, again, using the build of g++ 4.2 provided by my manufacturer.
Data (Release): | function | function (static empty) time/call | 3.54e-07s | 3.51e-07s space/type | 64B | 80B
Data (Debug): | function | function (static empty) time/call | 2.05e-06s | 2.04e-06s space/type | 64B | 80B
You can see that removing the empty check from boost::function yields about a 1% improvement in time per call to boost::signal. The increased space per type overhead is the same as before: 16B.
[...]
[Butting in after only vaguely following this thread...]
Would it also be appropriate to measure the "space/call", in addition to "time/call" and "space/type"? Or is there no difference, or had this been addressed already?
Well, a call to boost::function does not cost any additional space. However, there is a space/object cost, which the other benchmark does measure. The space overhead per boost::function object is constant. On my machine it's 32B for both of the empty state schemes. Daniel Walker

On Sat, Nov 6, 2010 at 10:22 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Tue, Nov 2, 2010 at 7:20 PM, Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> wrote:
On 11/02/2010 02:50 PM, Daniel Walker wrote: [...]
Here are the results I got, again, using the build of g++ 4.2 provided by my manufacturer.
Data (Release): | function | function (static empty) time/call | 3.54e-07s | 3.51e-07s space/type | 64B | 80B
Data (Debug): | function | function (static empty) time/call | 2.05e-06s | 2.04e-06s space/type | 64B | 80B
You can see that removing the empty check from boost::function yields about a 1% improvement in time per call to boost::signal. The increased space per type overhead is the same as before: 16B.
[...]
[Butting in after only vaguely following this thread...]
Would it also be appropriate to measure the "space/call", in addition to "time/call" and "space/type"? Or is there no difference, or had this been addressed already?
Well, a call to boost::function does not cost any additional space. However, there is a space/object cost, which the other benchmark does measure. The space overhead per boost::function object is constant. On my machine it's 32B for both of the empty state schemes.
Can someone please explain why does storing the empty state take space per type? Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Sat, Nov 6, 2010 at 2:08 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Sat, Nov 6, 2010 at 10:22 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Tue, Nov 2, 2010 at 7:20 PM, Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> wrote:
On 11/02/2010 02:50 PM, Daniel Walker wrote: [...]
Here are the results I got, again, using the build of g++ 4.2 provided by my manufacturer.
Data (Release): | function | function (static empty) time/call | 3.54e-07s | 3.51e-07s space/type | 64B | 80B
Data (Debug): | function | function (static empty) time/call | 2.05e-06s | 2.04e-06s space/type | 64B | 80B
You can see that removing the empty check from boost::function yields about a 1% improvement in time per call to boost::signal. The increased space per type overhead is the same as before: 16B.
[...]
[Butting in after only vaguely following this thread...]
Would it also be appropriate to measure the "space/call", in addition to "time/call" and "space/type"? Or is there no difference, or had this been addressed already?
Well, a call to boost::function does not cost any additional space. However, there is a space/object cost, which the other benchmark does measure. The space overhead per boost::function object is constant. On my machine it's 32B for both of the empty state schemes.
Can someone please explain why does storing the empty state take space per type?
Storing a target function takes space per type, namely, the static stored_vtable on line 912 of boost/function/function_template.hpp, which is dependent on both the type of boost::funciton's signature and the type of the target function. If the empty state is represented by a special "empty" target function, then this requires space to store the "empty" target function. We can move around where that space is consumed: it could be in the writable, initialized static data section, or we could move it to constant static data in the text segment. Regardless, the empty state must be either represented using memory or computed dynamically. As they say, there's no such thing as a free lunch. If boost::function is going to have two states, then those two states come at a cost. We can pay for them with either an extra static vtable in the executable or an extra pointer comparison, which in many cases can be optimized away by the compiler. The exact expense depends on the user's circumstance, which is why I think users should have the option to choose between the two schemes. Daniel Walker

Daniel Walker wrote: On Sat, Nov 6, 2010 at 2:08 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
Can someone please explain why does storing the empty state take space per type?
Storing a target function takes space per type, namely, the static stored_vtable on line 912 of boost/function/function_template.hpp, which is dependent on both the type of boost::funciton's signature and the type of the target function.
It doesn't have to. void throw_bad_function_call() { throw bad_function_call(); } function<void()> f( &throw_bad_function_call ); doesn't take up any additional space per type, unless of course the program never stores a function pointer into function<>. You just need one "empty" bit to avoid the DLL problems with the function not having an unique address. It doesn't take up any additional space in the code segment either, because this "throw_bad_function_call" function ought to be present in the current implementation somewhere; either that, or it's being inlined per every function<> call, which is even worse.

On Sat, Nov 6, 2010 at 7:53 PM, Peter Dimov <pdimov@pdimov.com> wrote:
Daniel Walker wrote: On Sat, Nov 6, 2010 at 2:08 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
Can someone please explain why does storing the empty state take space per type?
Storing a target function takes space per type, namely, the static stored_vtable on line 912 of boost/function/function_template.hpp, which is dependent on both the type of boost::funciton's signature and the type of the target function.
It doesn't have to.
void throw_bad_function_call() { throw bad_function_call(); }
function<void()> f( &throw_bad_function_call );
doesn't take up any additional space per type, unless of course the program never stores a function pointer into function<>.
This is a special case: all targets are function pointers of the same type, right? However, this defeats the purpose of boost::function. If all targets are the same type, the user doesn't need to use boost::function in the first place! This is not a motivating use case. The user would be better off using the target type directly or making the type a template parameter as the std algorithms do. boost::function is a polymorphic function wrapper; it is used to store callable objects of different types and that's the problem domain we should focus on. It's interesting to think about and thanks for bringing it up, but I don't believe it is worthwhile to optimize boost::function for use cases that are tangential to its problem domain.
<snip> It doesn't take up any additional space in the code segment either,
On my system, the text segment grows by up to 14% when boost::function( &throw_bad_function_call ) is used for empty wrappers. The reason is because of the extra template instantiations needed to support the type of throw_bad_function_call, which may not be the same as the type of any other target. Daniel Walker

Daniel Walker wrote: On Sat, Nov 6, 2010 at 7:53 PM, Peter Dimov <pdimov@pdimov.com> wrote:
void throw_bad_function_call() { throw bad_function_call(); }
function<void()> f( &throw_bad_function_call );
doesn't take up any additional space per type, unless of course the program never stores a function pointer into function<>.
This is a special case: all targets are function pointers of the same type, right?
No. It's enough for one of them to be.
On my system, the text segment grows by up to 14% when boost::function( &throw_bad_function_call ) is used for empty wrappers.
It's very uncommon for real code to not already contain the necessary instantiations or the equivalent of throw_bad_function_call itself. As soon as you put a function pointer into boost::function, you ought to get the instantiations; and as soon as you call it, you ought to get code that throws bad_function_call. Or I may be missing something.

On Sun, Nov 7, 2010 at 4:14 PM, Peter Dimov <pdimov@pdimov.com> wrote:
Daniel Walker wrote: On Sat, Nov 6, 2010 at 7:53 PM, Peter Dimov <pdimov@pdimov.com> wrote:
void throw_bad_function_call() { throw bad_function_call(); }
function<void()> f( &throw_bad_function_call );
doesn't take up any additional space per type, unless of course the > program never stores a function pointer into function<>.
This is a special case: all targets are function pointers of the same type, right?
No. It's enough for one of them to be.
Oh, I see, if the user ever assigns a function pointer target, then you can reuse the vtable from the empty target. OK, that's a reasonable optimization, but it doesn't decrease the upper bound on space overhead, which is reached when no user-assigned target has the same type as the empty target.
On my system, the text segment grows by up to 14% when boost::function( &throw_bad_function_call ) is used for empty wrappers.
It's very uncommon for real code to not already contain the necessary instantiations or the equivalent of throw_bad_function_call itself.
Actually, I just saw a real world example the other day. The benchmark that Domagoj suggested (the Boost.Signal benchmark code from Christophe Prud'homme) does not use function pointers and would not benefit from your suggestion. So, I don't think we can assume it is uncommon for boost::function to be used without function pointers. (On a personal note, the first time I started using boost::function was to store the return value of boost::bind, so none of my old code assigned boost::function with a function pointer. I imagine there are others who came down the same road as me.)
As soon as you put a function pointer into boost::function, you ought to get the instantiations; and as soon as you call it, you ought to get code that throws bad_function_call. Or I may be missing something.
No, you're correct with respect to the text segment. You get all the instantiations from the first function pointer target. However, if the user does not assign a function pointer, then the increased text segment overhead from using an "empty" function pointer approaches 14% on my system. Again, all of this just further illustrates that the costs and benefits of the static empty scheme vary according to circumstances. Some users will experience little cost and/or little benefit. Those who decide that the benefit merits the cost can choose to use the alternative scheme. But I see no reason to increase the costs for any user when there is no guarantee that there will be some benefit. The benchmarks demonstrate that removing the null pointer check from operator() does not always yield a significant time savings. Daniel Walker

"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTinCj3avcSZtfm9jcCBfmcDVDbSyf4Cu8ZktumwY@mail.gmail.com...
On Sat, Nov 6, 2010 at 7:53 PM, Peter Dimov <pdimov@pdimov.com> wrote:
This is a special case: all targets are function pointers of the same type, right?
No. It's enough for one of them to be.
Oh, I see, if the user ever assigns a function pointer target, then you can reuse the vtable from the empty target. OK, that's a reasonable optimization, but it doesn't decrease the upper bound on space overhead, which is reached when no user-assigned target has the same type as the empty target.
That is not an optimization, it is just the correct way to do it and the way the current boost::function implementation already functions... -- "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, Nov 8, 2010 at 7:24 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTinCj3avcSZtfm9jcCBfmcDVDbSyf4Cu8ZktumwY@mail.gmail.com...
On Sat, Nov 6, 2010 at 7:53 PM, Peter Dimov <pdimov@pdimov.com> wrote:
This is a special case: all targets are function pointers of the same type, right?
No. It's enough for one of them to be.
Oh, I see, if the user ever assigns a function pointer target, then you can reuse the vtable from the empty target. OK, that's a reasonable optimization, but it doesn't decrease the upper bound on space overhead, which is reached when no user-assigned target has the same type as the empty target.
That is not an optimization, it is just the correct way to do it and the way the current boost::function implementation already functions...
There is more than one "correct" way to implement the empty static scheme. The current boost::function implementation does not implement an empty target. The implementation of the empty static scheme in my previous patch could be optimized using Peter's suggestion. I looked into this optimization further and found that it doesn't work for all function pointer targets, since not all function pointer targets have the same type as the empty target. Consider the following: int f(int) { return 0; } int main() { boost::function<float(float)> g; g = &f; } This is a perfectly valid function pointer assignment, but the empty target function pointer from the first line of main would have a different type than the user assigned function pointer on the second line. So, in this case, the static empty vtable cannot be reused to store &f. However, in the case where the user does assign a function pointer with the same type as the empty target, it seems like a good idea to reuse the empty vtable per Peter's suggestion. I uploaded a new patch that implements this optimization as well as the const static vtable from ticket 4717, so that all space overhead is in the text segment. https://svn.boost.org/trac/boost/ticket/4803 Peter, if you have time, would you mind taking a look at my patch? Let me know what you think and if you see any other areas for improvement. Thanks! Daniel Walker

On 6 November 2010 13:08, Emil Dotchevski <emil@revergestudios.com> wrote:
Can someone please explain why does storing the empty state take space per type?
Is it a side effect of being a header only library? -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404

"Nevin Liber" <nevin@eviloverlord.com> wrote in message news:AANLkTi=iE8V4grniB1HgXeBJNBUG0gVyKHpGW+7wHczo@mail.gmail.com...
On 6 November 2010 13:08, Emil Dotchevski <emil@revergestudios.com> wrote:
Can someone please explain why does storing the empty state take space per type?
Is it a side effect of being a header only library?
No, but because each target type requires/is invoked by different (source and/or generated) code so it needs a different vtable that points to the different invoker code... e.g. different code is used to invoke a free function pointer, a bound member function, a lambda expression, a referenced boost function etc etc... -- "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 11/6/2010 10:22 AM, Daniel Walker wrote:
On Tue, Nov 2, 2010 at 7:20 PM, Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> wrote:
On 11/02/2010 02:50 PM, Daniel Walker wrote: [...]
Here are the results I got, again, using the build of g++ 4.2 provided by my manufacturer.
Data (Release): | function | function (static empty) time/call | 3.54e-07s | 3.51e-07s space/type | 64B | 80B
Data (Debug): | function | function (static empty) time/call | 2.05e-06s | 2.04e-06s space/type | 64B | 80B
You can see that removing the empty check from boost::function yields about a 1% improvement in time per call to boost::signal. The increased space per type overhead is the same as before: 16B.
[...]
[Butting in after only vaguely following this thread...]
Would it also be appropriate to measure the "space/call", in addition to "time/call" and "space/type"? Or is there no difference, or had this been addressed already?
Well, a call to boost::function does not cost any additional space.
I'm not sure what you mean. "Additional" to what? Isn't the underlying dispatching code different for the 2 implementations of boost::function you're comparing above? I.e., one has a null-pointer check, while the other doesn't. One might hypothesize that the dispatching code that must perform a null-pointer check will compile to more instructions than the dispatching code that does not perform a null-pointer check, and I presume the timings above support this hypothesis. I would think this should lead to variations in the size of the code segment. This variation might be more pronounced if the dispatching were inlined. I'm just speculating... - Jeff

On Sat, Nov 6, 2010 at 5:31 PM, Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> wrote:
On 11/6/2010 10:22 AM, Daniel Walker wrote:
On Tue, Nov 2, 2010 at 7:20 PM, Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> wrote:
On 11/02/2010 02:50 PM, Daniel Walker wrote: [...]
Here are the results I got, again, using the build of g++ 4.2 provided by my manufacturer.
Data (Release): | function | function (static empty) time/call | 3.54e-07s | 3.51e-07s space/type | 64B | 80B
Data (Debug): | function | function (static empty) time/call | 2.05e-06s | 2.04e-06s space/type | 64B | 80B
You can see that removing the empty check from boost::function yields about a 1% improvement in time per call to boost::signal. The increased space per type overhead is the same as before: 16B.
[...]
[Butting in after only vaguely following this thread...]
Would it also be appropriate to measure the "space/call", in addition to "time/call" and "space/type"? Or is there no difference, or had this been addressed already?
Well, a call to boost::function does not cost any additional space.
I'm not sure what you mean. "Additional" to what?
In addition to not calling boost::function. All of the additional space overhead is incurred when boost::function is instantiated (and assigned). No additional space overhead is incurred when an instantiated object is called at runtime, though of course the call does take up space for code in the text segment.
Isn't the underlying dispatching code different for the 2 implementations of boost::function you're comparing above? I.e., one has a null-pointer check, while the other doesn't. One might hypothesize that the dispatching code that must perform a null-pointer check will compile to more instructions than the dispatching code that does not perform a null-pointer check, and I presume the timings above support this hypothesis. I would think this should lead to variations in the size of the code segment. This variation might be more pronounced if the dispatching were inlined. I'm just speculating...
Yes, the text segment size also changes. And in fact, I believe, we could move the space overhead in the data segment to the text segment by making the static initialized vtable constant, as was suggested earlier in this thread. So, the text segment size could be more important in determining the expense of the static empty scheme. Daniel Walker

"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTin+bj=YeGtpo7sqLMUq2Nx3uG_teEFbcDMsM5Eb@mail.gmail.com...
On Tue, Nov 2, 2010 at 7:20 PM, Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> wrote:
Would it also be appropriate to measure the "space/call", in addition to "time/call" and "space/type"? Or is there no difference, or had this been addressed already?
Well, a call to boost::function does not cost any additional space.
How (or better, why) can you possibly claim something as plainly false as this..? That this is false is obvious to anyone just following the discussion (and all the talk about the redundant if empty then throw logic/code) not to mention to someone that actually poked around the source code or even looked at the generated code.... -- "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, Nov 8, 2010 at 7:24 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTin+bj=YeGtpo7sqLMUq2Nx3uG_teEFbcDMsM5Eb@mail.gmail.com...
On Tue, Nov 2, 2010 at 7:20 PM, Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> wrote:
Would it also be appropriate to measure the "space/call", in addition to "time/call" and "space/type"? Or is there no difference, or had this been addressed already?
Well, a call to boost::function does not cost any additional space.
How (or better, why) can you possibly claim something as plainly false as this..?
That this is false is obvious to anyone just following the discussion (and all the talk about the redundant if empty then throw logic/code) not to mention to someone that actually poked around the source code or even looked at the generated code....
boost::function allocates space when it is instantiated and assigned (e.g. line 580 of function_template.hpp), but not during a call to boost::function. Perhaps, you are referring to stack allocation? Yes, a call to boost::function could result in the stack growing, but that wasn't the question. If you are referring to the memory in the text section of the executable used to define operator() itself, yes, that's obvious, this is another space expense per type, but that wasn't the question. If you are aware of some other memory which is consumed during a call to boost::function, could you please be specific and include line numbers? Daniel Walker

On 11/13/2010 10:39 AM, Daniel Walker wrote:
On Mon, Nov 8, 2010 at 7:24 PM, Domagoj Saric<dsaritz@gmail.com> wrote:
"Daniel Walker"<daniel.j.walker@gmail.com> wrote in message news:AANLkTin+bj=YeGtpo7sqLMUq2Nx3uG_teEFbcDMsM5Eb@mail.gmail.com...
On Tue, Nov 2, 2010 at 7:20 PM, Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> wrote:
Would it also be appropriate to measure the "space/call", in addition to "time/call" and "space/type"? Or is there no difference, or had this been addressed already?
Well, a call to boost::function does not cost any additional space.
How (or better, why) can you possibly claim something as plainly false as this..?
That this is false is obvious to anyone just following the discussion (and all the talk about the redundant if empty then throw logic/code) not to mention to someone that actually poked around the source code or even looked at the generated code....
boost::function allocates space when it is instantiated and assigned (e.g. line 580 of function_template.hpp), but not during a call to boost::function. Perhaps, you are referring to stack allocation? Yes, a call to boost::function could result in the stack growing, but that wasn't the question. If you are referring to the memory in the text section of the executable used to define operator() itself, yes, that's obvious, this is another space expense per type, but that wasn't the question. If you are aware of some other memory which is consumed during a call to boost::function, could you please be specific and include line numbers?
Actually, my original question was regarding space/call, with "space" referring to the same thing as your "space/type", i.e., space in the executable (in this case, the text segment). I believe I clarified this in a later post (no link handy). Sorry, I thought the context of the question made the terminology unambiguous. - Jeff

On Sat, Nov 13, 2010 at 2:45 PM, Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> wrote> On 11/13/2010 10:39 AM, Daniel Walker wrote:
On Mon, Nov 8, 2010 at 7:24 PM, Domagoj Saric<dsaritz@gmail.com> wrote:
"Daniel Walker"<daniel.j.walker@gmail.com> wrote in message news:AANLkTin+bj=YeGtpo7sqLMUq2Nx3uG_teEFbcDMsM5Eb@mail.gmail.com...
On Tue, Nov 2, 2010 at 7:20 PM, Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> wrote:
Would it also be appropriate to measure the "space/call", in addition to "time/call" and "space/type"? Or is there no difference, or had this been addressed already?
Well, a call to boost::function does not cost any additional space.
How (or better, why) can you possibly claim something as plainly false as this..?
That this is false is obvious to anyone just following the discussion (and all the talk about the redundant if empty then throw logic/code) not to mention to someone that actually poked around the source code or even looked at the generated code....
boost::function allocates space when it is instantiated and assigned (e.g. line 580 of function_template.hpp), but not during a call to boost::function. Perhaps, you are referring to stack allocation? Yes, a call to boost::function could result in the stack growing, but that wasn't the question. If you are referring to the memory in the text section of the executable used to define operator() itself, yes, that's obvious, this is another space expense per type, but that wasn't the question. If you are aware of some other memory which is consumed during a call to boost::function, could you please be specific and include line numbers?
Actually, my original question was regarding space/call, with "space" referring to the same thing as your "space/type", i.e., space in the executable (in this case, the text segment). I believe I clarified this in a later post (no link handy). Sorry, I thought the context of the question made the terminology unambiguous.
OK, thanks for the clarification. The space per type in the text segment is now the only space overhead of the static empty scheme, since the static vtable assignment can be made const. So the size in the text segment is now the only important question. :) I re-ran the two benchmarks attached to the Trac ticket using gcc 4.2 and report the results below including text segment size. Function Benchmark Data (Release): | current | static empty time/call | 6.69e-09s | 6.26e-09s space/obj | 32B | 32B space/type (data)* | 32B | 32B space/type (text) | 6347B | 7386B Signal Benchmark Data (Release): | current | static empty time/call** | 1.55e-07s | 1.57e-07s space/obj | N/A | N/A space/type (data)* | 32B | 32B space/type (text) | 46539B | 47361B * Total size of the initialized static data section of the data segment, which shows that boost::function's contribution is 0B. ** On my machine these times are not consistent with every run. Sometimes the static empty scheme is up to 9% faster. So, you can see that the static empty scheme may or may not yield some time savings, but it does increase the total size of the text section by around 1000B in both tests. Again all of this is highly dependent on the compiler optimization and the specific circumstance in which it is used, which is why users should be given the choice as to whether or not to enable the static empty scheme. Daniel Walker

"Jeffrey Lee Hellrung, Jr." <jhellrung@ucla.edu> wrote in message news:4CD09CD7.9090501@ucla.edu...
Would it also be appropriate to measure the "space/call", in addition to "time/call" and "space/type"? Or is there no difference, or had this been addressed already?
If you have not already noticed, you might be interested in http://lists.boost.org/Archives/boost/2010/10/172593.php ;) -- "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

"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTinT6ofcXAi3TsBCDoDqLVgLn-sK4g0pV9pPOGu7@mail.gmail.com...
On Sat, Oct 30, 2010 at 1:25 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
e.g. http://lists.boost.org/Archives/boost/2010/01/160908.php
Thanks. I added a tarball, signal_benchmark.tar.bz2, with a jamfile and source code so that anyone who's interested can easily reproduce this benchmark. The benchmark measures the impact of the static empty scheme on the time per call of boost::signals2::signal using the code Domagoj linked to. Thanks to Christophe Prud'homme for the original benchmark!
Here are the results I got, again, using the build of g++ 4.2 provided by my manufacturer.
Data (Release): | function | function (static empty) time/call | 3.54e-07s | 3.51e-07s space/type | 64B | 80B
Data (Debug): | function | function (static empty) time/call | 2.05e-06s | 2.04e-06s space/type | 64B | 80B
You can see that removing the empty check from boost::function yields about a 1% improvement in time per call to boost::signal. The increased space per type overhead is the same as before: 16B.
You just missed one important detail mentioned in the original post which is to use a dummy mutex... The fact that you were able to consistently measure _any_ difference (even with your own simple modification) for something that should ideally be a 'simple' indirect call while 'surrounded' with all the dynamic memory allocations, mutex locking, local shared_ptr/guard objects and other complex internal signals2 logic... speaks volumes about the actual overhead at hand (for which you now seem to want to claim as insignificant)... You also misinterpreted the benchmark itself and used an incorrect 'formula'/logic to count the number of boost::function invocations. Note that this is/was a boost::signals(2) benchmark and the number of boost::function invocations is not the same as the number of boost::signal(2) invocations...for example 25% of the time the benchmark code you posted is invoking a signal with no handler/boost::function assigned at all (that you take into account as boost::function invocations)...Even when the count part of the 'formula' is corrected, the end result 'name', 'average time per call', is still a misnomer as the calculation still/also includes signal creation, 'resizing' etc (which OTOH then also implictly benchmarks boost::function copy-construction and assignment, another sub-optimal area of the current implementation)... The correct way to use and interpret the benchmark is exactly the way its original author did...to simply compare total times (for intermediate sizes or for the whole benchmark)... Additionally the N chosen is IMO not large enough for the latest architectures (e.g. an i5@4+ GHz that also constantly dynamically adjusts its frequency) to achieve stable enough results... The patch provided switches to a dummy mutex, adds two zeros to N, adjusts the benchmark's priority, corrects the number-of-calls calculation and skips the invocation of empty signals... The differences in the 'average-time-per-call-that-is-actually-something-else' number that the benchmark, patched and compiled with MSVC++ 10 (/Oxs), shows between https://svn.boost.org/svn/boost/sandbox/function/boost/function and https://svn.boost.org/svn/boost/trunk/boost/function are Via C7-M ~6% Intel i5 ~8% AMD Athlon64 ~24% (Yes, the Athlon number is correct, I measured it several times...if there is an AMD architecture expert lurking around here I'd love to hear his/hers thoughts about the result ;)
So, basically, in the use-case measured by this benchmark the time overhead of boost::function is dwarfed by the combined costs of boost::signal and the target function, and so using the static empty scheme does not yield much benefit.
Even if it were 'dwarfed' (which it isn't) that result would still not imply that the change is somehow irrelevant or not worth doing (if there are no drawbacks to it, and there aren't, aiming specifically at your claims/'concerns' about static space size)... Justifying inefficient code with the fact that there exists even slower code that wraps it is just downright wrong (even though so frequently done) as the same logic could then be used to justify just about any bad thing in the Universe since you can always find something worse... -- "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, Nov 8, 2010 at 7:19 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTinT6ofcXAi3TsBCDoDqLVgLn-sK4g0pV9pPOGu7@mail.gmail.com...
On Sat, Oct 30, 2010 at 1:25 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
e.g. http://lists.boost.org/Archives/boost/2010/01/160908.php
Thanks. I added a tarball, signal_benchmark.tar.bz2, with a jamfile and source code so that anyone who's interested can easily reproduce this benchmark. The benchmark measures the impact of the static empty scheme on the time per call of boost::signals2::signal using the code Domagoj linked to. Thanks to Christophe Prud'homme for the original benchmark!
Here are the results I got, again, using the build of g++ 4.2 provided by my manufacturer.
Data (Release): | function | function (static empty) time/call | 3.54e-07s | 3.51e-07s space/type | 64B | 80B
Data (Debug): | function | function (static empty) time/call | 2.05e-06s | 2.04e-06s space/type | 64B | 80B
You can see that removing the empty check from boost::function yields about a 1% improvement in time per call to boost::signal. The increased space per type overhead is the same as before: 16B.
You just missed one important detail mentioned in the original post which is to use a dummy mutex...
I simply ran the code you linked to.
<snip> The patch provided switches to a dummy mutex, adds two zeros to N, adjusts the benchmark's priority, corrects the number-of-calls calculation and skips the invocation of empty signals...
OK, I applied your patch, and I uploaded a new tar ball to ticket 4803 incorporating your changes. Here are the new timing results on my system's gcc 4.2 in release mode. Data (Release): | function | function (static empty) time/call | 1.73e-07s | 1.57e-07s So, in this case, you can see that the static empty scheme yields about a 9% improvement in the average time of the test function (normalized by the number of slots and calls). So, again, this shows that it is possible that some users could experience some benefit from the static empty scheme, and we should allow them the opportunity to experiment, determine what works best for their project and choose the appropriate configuration option. Daniel Walker

"Doug Gregor" <doug.gregor@gmail.com> wrote in message news:AANLkTimkWbdBaTe_4+uF4fDLcdC0yUgQ-c7eOKs_dryK@mail.gmail.com...
On Wed, Oct 20, 2010 at 1:51 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
There would need to be a different "empty" vtable each time boost::function is instantiated with a different call signature, so that the "empty" vtable can be used seamlessly by operator() for any call signature.
One per boost::function signature, yes.
Actually, vtables are statically allocated one per "boost::function<> signature + target function object type" combination. The consequence of this is that if you assign a target to a b.function that has the same type as the on-empty-handler target there is/will be no (static space) overhead... The more different types of targets you assign to a b.function the additional overhead of an on-empty-handler target (if any as explained above) becomes relatively smaller and smaller... Moreover, even the above is almost irrelevant considering that: - the cdecl calling convention enables you to have a single throw-on-empty target vtable per binary/for all boost::function<> instantiations - the static overhead of two pointers is truly insignificant compared to other (unnecessary) code-bloat overheads inherent to the current implementation (including the usually inlined if-empty-then-throw code)... For example, in my implementation the vtable has four pointers but, in comparison to the improvements in both code size and code speed that this change made possible, this overhead is hardly worth noting (in fact it can hardly be called real overhead if it enables the reduction of the overhead of boost::function<> as a whole)... -- "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 Thu, Oct 21, 2010 at 2:25 AM, Doug Gregor <doug.gregor@gmail.com> wrote:
On Wed, Oct 20, 2010 at 1:51 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
So, adding "empty" vtable objects would increase the space requirements of boost::function; each template instantiation would need two corresponding vtable objects, one for actual targets and one as a fallback that throws bad_function_call. (The "empty" vtable objects could be stored statically, but static storage is also a very precious resource on many platforms.) Not all users would appreciate this trade-off; i.e. an increase in the space overhead for a small decrease in time overhead (with compiler optimization the time savings are minuscule, in my experience).
Without quantifying the trade-off, we don't know which way is better.
In any case, this issue is fairly easy to settle; it just takes effort. Someone implements this alternative scheme and determines the cost/benefit in space and time, and with any luck the choice is obvious.
OK, I implemented the alternative scheme and ran some benchmarks to determine the cost/benefit in space/time. The code is in a Trac ticket with a patch that allows boost::function to be configured to represent its empty state using a static object that contains an "empty" function which calls boost::throw_exception when invoked. The user may select the alternative scheme by defining the macro BOOST_FUNCTION_USE_STATIC_EMPTY. https://svn.boost.org/trac/boost/ticket/4803 I also attached a tarball to the ticket with a Jamfile and source code to compile and run benchmarks of a function pointer, boost::function, and boost::function using the static empty scheme. The time overhead per call and space overhead per object are measured by the executables at runtime. The space overhead per type is the size of the static initialized date section in the executable's data segment as reported by /usr/bin/size. The following results were obtained on a x86 machine running an Unix variant using the manufacture's build of gcc 4.2. The machine was not in a labratory environment, so I am not controlling for changes in operating tempature that could impact performance at these time scales. The following tables present the raw numbers from bjam's release and debug builds. (See the Jamfile for the complete arguments to bjam.) Data (Release): | funcion ptr | function | function (static empty) time/call | 6.28e-10s | 6.68e-09s | 6.40e-09s space/type | 32B | 48B | 64B space/obj | 8B | 32B | 32B Result (Release): Defining BOOST_FUNCTION_USE_STATIC_EMPTY yields a 4% decrease in time overhead per call but doubles the space overhead per type. (On msvc 10 the decrease in time overhead is closer to 10%.) Data (Debug): | funcion ptr | function | function (static empty) time/call | 6.33e-09s | 2.62e-08s | 2.26e-08s space/type | 32B | 48B | 64B space/obj | 8B | 32B | 32B Result (Debug): Defining BOOST_FUNCTION_USE_STATIC_EMPTY yields a 18% decrease in time overhead per call but doubles the space overhead per type. So, I think the current boost::function implementation is certainly the right default, since many users would not appreciate doubling the static space overhead for a time savings of less than 10% per call. However, I think it is a good idea to offer users the opertunity to tinker and experiment with this trade-off, so that they can choose what works best for their application. Daniel Walker

Daniel Walker wrote:
On Thu, Oct 21, 2010 at 2:25 AM, Doug Gregor <doug.gregor@gmail.com> wrote:
On Wed, Oct 20, 2010 at 1:51 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
So, adding "empty" vtable objects would increase the space requirements of boost::function; each template instantiation would need two corresponding vtable objects, one for actual targets and one as a fallback that throws bad_function_call. (The "empty" vtable objects could be stored statically, but static storage is also a very precious resource on many platforms.) Not all users would appreciate this trade-off; i.e. an increase in the space overhead for a small decrease in time overhead (with compiler optimization the time savings are minuscule, in my experience). Without quantifying the trade-off, we don't know which way is better.
In any case, this issue is fairly easy to settle; it just takes effort. Someone implements this alternative scheme and determines the cost/benefit in space and time, and with any luck the choice is obvious.
OK, I implemented the alternative scheme and ran some benchmarks to determine the cost/benefit in space/time. The code is in a Trac ticket with a patch that allows boost::function to be configured to represent its empty state using a static object that contains an "empty" function which calls boost::throw_exception when invoked. The user may select the alternative scheme by defining the macro BOOST_FUNCTION_USE_STATIC_EMPTY.
https://svn.boost.org/trac/boost/ticket/4803
I also attached a tarball to the ticket with a Jamfile and source code to compile and run benchmarks of a function pointer, boost::function, and boost::function using the static empty scheme. The time overhead per call and space overhead per object are measured by the executables at runtime. The space overhead per type is the size of the static initialized date section in the executable's data segment as reported by /usr/bin/size.
The following results were obtained on a x86 machine running an Unix variant using the manufacture's build of gcc 4.2. The machine was not in a labratory environment, so I am not controlling for changes in operating tempature that could impact performance at these time scales. The following tables present the raw numbers from bjam's release and debug builds. (See the Jamfile for the complete arguments to bjam.)
Data (Release): | funcion ptr | function | function (static empty) time/call | 6.28e-10s | 6.68e-09s | 6.40e-09s space/type | 32B | 48B | 64B space/obj | 8B | 32B | 32B
Result (Release): Defining BOOST_FUNCTION_USE_STATIC_EMPTY yields a 4% decrease in time overhead per call but doubles the space overhead per type. (On msvc 10 the decrease in time overhead is closer to 10%.)
Data (Debug): | funcion ptr | function | function (static empty) time/call | 6.33e-09s | 2.62e-08s | 2.26e-08s space/type | 32B | 48B | 64B space/obj | 8B | 32B | 32B
Result (Debug): Defining BOOST_FUNCTION_USE_STATIC_EMPTY yields a 18% decrease in time overhead per call but doubles the space overhead per type.
So, I think the current boost::function implementation is certainly the right default, since many users would not appreciate doubling the static space overhead for a time savings of less than 10% per call. However, I think it is a good idea to offer users the opertunity to tinker and experiment with this trade-off, so that they can choose what works best for their application.
I've followed this thread only peripherally, but the important info to me would be does removing the check for empty function affect the optimized performance/code-size for the non-empty scenarios? In my experience, these are the scenarios most often encountered. Thanks, Jeff

On Fri, Oct 29, 2010 at 4:13 PM, Jeff Flinn <TriumphSprint2000@hotmail.com> wrote:
Daniel Walker wrote:
On Thu, Oct 21, 2010 at 2:25 AM, Doug Gregor <doug.gregor@gmail.com> wrote:
On Wed, Oct 20, 2010 at 1:51 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
So, adding "empty" vtable objects would increase the space requirements of boost::function; each template instantiation would need two corresponding vtable objects, one for actual targets and one as a fallback that throws bad_function_call. (The "empty" vtable objects could be stored statically, but static storage is also a very precious resource on many platforms.) Not all users would appreciate this trade-off; i.e. an increase in the space overhead for a small decrease in time overhead (with compiler optimization the time savings are minuscule, in my experience).
Without quantifying the trade-off, we don't know which way is better.
In any case, this issue is fairly easy to settle; it just takes effort. Someone implements this alternative scheme and determines the cost/benefit in space and time, and with any luck the choice is obvious.
OK, I implemented the alternative scheme and ran some benchmarks to determine the cost/benefit in space/time. The code is in a Trac ticket with a patch that allows boost::function to be configured to represent its empty state using a static object that contains an "empty" function which calls boost::throw_exception when invoked. The user may select the alternative scheme by defining the macro BOOST_FUNCTION_USE_STATIC_EMPTY.
https://svn.boost.org/trac/boost/ticket/4803
I also attached a tarball to the ticket with a Jamfile and source code to compile and run benchmarks of a function pointer, boost::function, and boost::function using the static empty scheme. The time overhead per call and space overhead per object are measured by the executables at runtime. The space overhead per type is the size of the static initialized date section in the executable's data segment as reported by /usr/bin/size.
The following results were obtained on a x86 machine running an Unix variant using the manufacture's build of gcc 4.2. The machine was not in a labratory environment, so I am not controlling for changes in operating tempature that could impact performance at these time scales. The following tables present the raw numbers from bjam's release and debug builds. (See the Jamfile for the complete arguments to bjam.)
Data (Release): | funcion ptr | function | function (static empty) time/call | 6.28e-10s | 6.68e-09s | 6.40e-09s space/type | 32B | 48B | 64B space/obj | 8B | 32B | 32B
Result (Release): Defining BOOST_FUNCTION_USE_STATIC_EMPTY yields a 4% decrease in time overhead per call but doubles the space overhead per type. (On msvc 10 the decrease in time overhead is closer to 10%.)
Data (Debug): | funcion ptr | function | function (static empty) time/call | 6.33e-09s | 2.62e-08s | 2.26e-08s space/type | 32B | 48B | 64B space/obj | 8B | 32B | 32B
Result (Debug): Defining BOOST_FUNCTION_USE_STATIC_EMPTY yields a 18% decrease in time overhead per call but doubles the space overhead per type.
So, I think the current boost::function implementation is certainly the right default, since many users would not appreciate doubling the static space overhead for a time savings of less than 10% per call. However, I think it is a good idea to offer users the opertunity to tinker and experiment with this trade-off, so that they can choose what works best for their application.
I've followed this thread only peripherally, but the important info to me would be does removing the check for empty function affect the optimized performance/code-size for the non-empty scenarios? In my experience, these are the scenarios most often encountered.
Yes, if you look at the code in the benchmark, you will see that it is measuring the cost of a call to a non-empty boost::function. In optimized object code, the call is 4% faster without the check, but removing the check means that it is necessary to store a special, internal static object per instantiation to hold an "empty" function that must be available if boost::function becomes empty. This static object doubles boost::function's space overhead in the initialized static data section of the executable's data segment. Daniel Walker

On Sat, Oct 30, 2010 at 9:43 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Yes, if you look at the code in the benchmark, you will see that it is measuring the cost of a call to a non-empty boost::function. In optimized object code, the call is 4% faster without the check, but removing the check means that it is necessary to store a special, internal static object per instantiation to hold an "empty" function that must be available if boost::function becomes empty.
Do you really need a placeholder for each different boost::function signature? Since all it does is throw an exception, it should be safe to use the same placeholder for all signatures: http://codepad.org/3GxiTHZA. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Sat, Oct 30, 2010 at 1:55 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Sat, Oct 30, 2010 at 9:43 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Yes, if you look at the code in the benchmark, you will see that it is measuring the cost of a call to a non-empty boost::function. In optimized object code, the call is 4% faster without the check, but removing the check means that it is necessary to store a special, internal static object per instantiation to hold an "empty" function that must be available if boost::function becomes empty.
Do you really need a placeholder for each different boost::function signature?
Yes. Internally, boost::function creates a static object for each signature to hold the target function. To hold the "empty" target function, it must create a second static object per signature: one for actual targets, one for an empty target.
Since all it does is throw an exception, it should be safe to use the same placeholder for all signatures: http://codepad.org/3GxiTHZA.
The issue is not whether we create a new _type_ for the placeholder per signature, but whether we create a new static _object_. So, adapting your example, the following makes your function look a little more like boost::function. template<class R, class T0, class T1> struct function { typedef R (*target_type)(T0,T1); target_type f; function() { static target_type stored_f = (target_type)&placeholder; f = stored_f; } R operator()(T0 a, T1 b) { f(a,b); } }; You can see that function<void, int, int> f; function<void, double, double> g; would create two static stored_f objects, one per instantiation, regardless of the type of placeholder. Good question! Daniel Walker

On 29 October 2010 15:02, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Result (Debug): Defining BOOST_FUNCTION_USE_STATIC_EMPTY yields a 18% decrease in time overhead per call but doubles the space overhead per type.
Does it? Presumably in the non-static-empty case the NULL pointer check and throw are getting inlined, resulting in more code space overhead the more times a given type is reused (which is typical, at least in my experience)? Projects low on static space tend to be low on code space as well. One would expect the code savings overhead to be amortized fairly quickly.
So, I think the current boost::function implementation is certainly the right default, since many users would not appreciate doubling the static space overhead for a time savings of less than 10% per call.
Is it? Projects low on static space usually don't have cycles to burn, either. -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404

On Fri, Oct 29, 2010 at 4:45 PM, Nevin Liber <nevin@eviloverlord.com> wrote:
On 29 October 2010 15:02, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Result (Debug): Defining BOOST_FUNCTION_USE_STATIC_EMPTY yields a 18% decrease in time overhead per call but doubles the space overhead per type.
Does it? Presumably in the non-static-empty case the NULL pointer check and throw are getting inlined, resulting in more code space overhead the more times a given type is reused (which is typical, at least in my experience)? Projects low on static space tend to be low on code space as well. One would expect the code savings overhead to be amortized fairly quickly.
Well, we can answer these questions empirically using the benchmark executables (see the Trac ticket for source code). On my system, the text section of the text segment grows from 3728B to 4608B when the static empty scheme is used. The reason that the static empty scheme increases the code size is that it increases the number of boost::function internal class and function templates instantiated in order to handle the "empty" function in addition to the actual target function.
So, I think the current boost::function implementation is certainly the right default, since many users would not appreciate doubling the static space overhead for a time savings of less than 10% per call.
Is it? Projects low on static space usually don't have cycles to burn, either.
I think users should have the opportunity to tinker and discover which scheme works best for their project. However, the current behavior seems like a good default. Remember, the benefit of the static empty scheme is dependent on the compiler optimization, the call context, etc. Depending on the user's situation, the new scheme could have no discernible benefit at all. However, in all situations the static empty scheme has a cost. Also, remember, we're talking about a difference of %4 of a call to boost::function, not 4% of the call to the actual target function. If the target function is very cheap, then boost::function overhead could matter. But the more cycles the target function consumes, the less significant the overhead of boost function. The applications that would benefit most from the static empty scheme are those that spend a significant portion of their cycles calling boost::function rather than doing actual work. I think it's safe to assume that this is not the norm. So, why force most users to increase their static space overhead for nothing? Daniel Walker

"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTimSdhEy=bQxj=mKkJG0d48kuCpXYnQz9DK2O_A0@mail.gmail.com...
So, I think the current boost::function implementation is certainly the right default, since many users would not appreciate doubling the static space overhead for a time savings of less than 10% per call.
I already explained to you that there is no 'double space overhead' with the condition that the change is done right or the linker is able to merge identical objects, neither of which is true in the case you posted. The 'double' overhead you got is actually not 'double' but one unnecessary vtable extra: - even in your implementation, if you assigned more (different typed) targets to a boost::function you'd get an additional vtable for each of those (different typed) targets...so the overhead, as said, is not double but one extra... - the problem with your implementation is that you copied the original assign() member function for your new "empty target" function copying with it the local static vtable...to do it right the vtable must not be a local (template) function static... Not to mention, as also already explained in more detail (and pointed to by Nevin), this 'overhead' of a few static pointers is completely insignificant compared to various related code bloat issues... -- "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

Domagoj Saric wrote:
this 'overhead' of a few static pointers is completely insignificant compared to various related code bloat issues...
That should be true. But unfortunately, the overhead of static pointers are actually significant while they are not const, at least for me. https://svn.boost.org/trac/boost/ticket/4717 -- k_satoda

"Kazutoshi Satoda" <k_satoda@f2.dion.ne.jp> wrote in message news:4CCCA801.7000209@f2.dion.ne.jp...
Domagoj Saric wrote:
this 'overhead' of a few static pointers is completely insignificant compared to various related code bloat issues...
That should be true. But unfortunately, the overhead of static pointers are actually significant while they are not const, at least for me.
In my implementation the vtables as well as the pointers inside them are const (actually they are references on compilers which support references to functions)...Actually my policy from the beginning was to make const just about everything that can be made const... ;) -- "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 Sat, Oct 30, 2010 at 5:19 PM, Kazutoshi Satoda <k_satoda@f2.dion.ne.jp> wrote:
Domagoj Saric wrote:
this 'overhead' of a few static pointers is completely insignificant compared to various related code bloat issues...
That should be true. But unfortunately, the overhead of static pointers are actually significant while they are not const, at least for me.
Okay, few questions, why 'require' it to have something, a null function pointer could be a valid case, just calling it causes UB. But since it is unsafe anyway, why use the operator() syntax for it, why not just do something like this (pick one, whatever is 'prettier'): boost::function<void(int)> f = fromSomewhere(); boost::function<void(int)> u; f(1); // current syntax, calls function, but after doing a null check u(1); // current syntax, throws f(unsafe_no_throw,1); // possible new syntax, calls function, no null check u(unsafe_no_throw,1); // possible new syntax, whatever the platform does when a null pointer is called f.unsafe_no_throw_call(1); // possible new syntax, possibly another name, calls function, no null check u.unsafe_no_throw_call(1); // possible new syntax, possibly another name, whatever the platform does when a null pointer is called There are other ways too of course, but yeah, why not just add another way to call the existing boost::function that calls it without the null check and without throwing, just with a precondition that it is not null, instead of testing it internally? That would solve the issues fine, and it is an 'advanced' feature so why not have an 'advanced' call for it?

On Mon, Nov 1, 2010 at 8:58 PM, OvermindDL1 <overminddl1@gmail.com> wrote:
f(unsafe_no_throw,1); // possible new syntax, calls function, no null check u(unsafe_no_throw,1); // possible new syntax, whatever the platform
This is somewhat redundant since you can already do assert(f); f(1); I was proposing a similar change, to add a boost::function constructor that takes std::nothrow_t, which can be used to initialize an empty function object which asserts and doesn't throw upon calling op(). However I'm not sure there is a use case even for this: it lets you pick throw or no-throw semantics, but no-throw semantics are only useful in BOOST_NO_EXCEPTIONS builds, and therefore the global no-throw behavior supported by boost::throw_exception should be sufficient. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Tue, Nov 2, 2010 at 1:17 AM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Mon, Nov 1, 2010 at 8:58 PM, OvermindDL1 <overminddl1@gmail.com> wrote:
f(unsafe_no_throw,1); // possible new syntax, calls function, no null check u(unsafe_no_throw,1); // possible new syntax, whatever the platform
This is somewhat redundant since you can already do
assert(f); f(1);
I was proposing a similar change, to add a boost::function constructor that takes std::nothrow_t, which can be used to initialize an empty function object which asserts and doesn't throw upon calling op(). However I'm not sure there is a use case even for this: it lets you pick throw or no-throw semantics, but no-throw semantics are only useful in BOOST_NO_EXCEPTIONS builds, and therefore the global no-throw behavior supported by boost::throw_exception should be sufficient.
With a smart enough optimizer, that should indeed remove the `if` check (my purpose of this), but that then adds an assert in the code that will still get run at runtime. The problem with adding a nothrow_t in the constructor is that state then needs to be held (or you need to templately-branch based on it, which would remove the runtime state requirement, but that is a lot of extra code to manage), but there are some places in code where calling a boost::function may very well possibly be null, and an exception may be warranted (like outside of my code), but other places (like inside of my code) I already know before-hand whether or not a function is null or not and whether or not to call it, even if I have no `if` check before its call, just based on how the program flow works. I just want it to call it, potentially inline it (which I have seen the optimizer do nicely enough), with no dang checks getting in the way. The called function might still throw, might not, who knows, I just do not want the check, and yes I have a use-case for it in tight loops (where currently a fastdelegate outperforms the identical code using boost::function by a rather healthy margin, and looking at the assembly, the only difference is the `if` check).

On Sat, Oct 30, 2010 at 7:19 PM, Kazutoshi Satoda <k_satoda@f2.dion.ne.jp> wrote:
Domagoj Saric wrote:
this 'overhead' of a few static pointers is completely insignificant compared to various related code bloat issues...
That should be true. But unfortunately, the overhead of static pointers are actually significant while they are not const, at least for me.
Thanks for following up on this. I looked into it and this seems like a good idea to me. I attached a patch to your ticket. Daniel Walker

On Sat, Oct 30, 2010 at 1:24 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTimSdhEy=bQxj=mKkJG0d48kuCpXYnQz9DK2O_A0@mail.gmail.com...
So, I think the current boost::function implementation is certainly the right default, since many users would not appreciate doubling the static space overhead for a time savings of less than 10% per call.
I already explained to you that there is no 'double space overhead' with the condition that the change is done right or the linker is able to merge identical objects, neither of which is true in the case you posted.
I'll try to give a brief outline to illustrate why adding a static vtable means there are at least two static vtables per signature. Here is what boost::function must do when you assign a target: static target_type stored_vtable = // target function vtable if(assign(stored_vtable, target_function)) // clone the function vtable = &stored_vtable; else vtable = NULL; Now, if instead we want vtable to point to a static empty object, we need to do something like the following. static target_type stored_vtable = // target function vtable if(assign(stored_vtable, target_function)) // clone the function vtable = &stored_vtable; else { static empty_target_type stored_empty_vtable = // empty target vtable assign(stored_empty_vtable, empty_function) // does not fail vtable = stored_empty_vtable; } Again this is a rough outline of boost::function assignment, but it gives you the idea. The reason you need two static initializations is that target_type and empty_target_type may not be the same type.
The 'double' overhead you got is actually not 'double' but one unnecessary vtable extra: - even in your implementation, if you assigned more (different typed) targets to a boost::function you'd get an additional vtable for each of those (different typed) targets...so the overhead, as said, is not double but one extra...
In the worst case scenario one extra vtable per signature _is_ double; i.e. in the worst case, the largest increase in overhead you can possibly see is 100%. I do not mean that there are at most two vtables; I mean there are at least two vtables instead of one.
- the problem with your implementation is that you copied the original assign() member function for your new "empty target" function copying with it the local static vtable...to do it right the vtable must not be a local (template) function static...
It doesn't matter whether the empty static assignment is in a different member function or not. boost::function will still require two static assignments: one for the actual target and one for the empty target.
Not to mention, as also already explained in more detail (and pointed to by Nevin), this 'overhead' of a few static pointers is completely insignificant compared to various related code bloat issues...
On some platforms the overhead of a few static pointers matters a great deal. Regardless, there's no reason to increase the static space overhead at all, if it does not improve time performance commensurately. Daniel Walker

"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTim_OqV7nV_Q7R6YanUHFMYPkM8i3Wsm6FpGrRNX@mail.gmail.com...
On Sat, Oct 30, 2010 at 1:24 PM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:AANLkTimSdhEy=bQxj=mKkJG0d48kuCpXYnQz9DK2O_A0@mail.gmail.com...
So, I think the current boost::function implementation is certainly the right default, since many users would not appreciate doubling the static space overhead for a time savings of less than 10% per call.
I already explained to you that there is no 'double space overhead' with the condition that the change is done right or the linker is able to merge identical objects, neither of which is true in the case you posted.
I'll try to give a brief outline to illustrate why adding a static vtable means there are at least two static vtables per signature.
Even if there were at least two vtables (which there aren't as already explained) this still does not constitute a 'double space overhead' which is what you were claiming...
Here is what boost::function must do when you assign a target:
static target_type stored_vtable = // target function vtable if(assign(stored_vtable, target_function)) // clone the function vtable = &stored_vtable; else vtable = NULL;
No, this is what current boost::function does not what it 'must' do...(I'm sorry I have to be picky because this whole thread has issues with lack of precise terminology, shifting/redefining the basic terms of the discussion and reasserting already proven-false claims)...
Now, if instead we want vtable to point to a static empty object, we need to do something like the following.
static target_type stored_vtable = // target function vtable if(assign(stored_vtable, target_function)) // clone the function vtable = &stored_vtable; else { static empty_target_type stored_empty_vtable = // empty target vtable assign(stored_empty_vtable, empty_function) // does not fail vtable = stored_empty_vtable; }
No, this is what your implementation does (which is why it is 'wrong', as already explained) not what 'we need to do'...
Again this is a rough outline of boost::function assignment, but it gives you the idea.
Thanks, I have a 'rough' idea of boost::function assignment as I've pretty much reimplemented it... If you want you can take a look at the assembly listings presented here http://lists.boost.org/Archives/boost/2010/10/172593.php that also demonstrate assignment...
The reason you need two static initializations is that target_type and empty_target_type may not be the same type.
Right, except that saying that they _may not_ be is also implying that they _may be_... which basically means that your claim to a 'double space overhead' is based on a 'maybe' something that even when happens still does not imply/result in a 'double space overhead'...
The 'double' overhead you got is actually not 'double' but one unnecessary vtable extra: - even in your implementation, if you assigned more (different typed) targets to a boost::function you'd get an additional vtable for each of those (different typed) targets...so the overhead, as said, is not double but one extra...
In the worst case scenario one extra vtable per signature _is_ double; i.e. in the worst case, the largest increase in overhead you can possibly see is 100%. I do not mean that there are at most two vtables; I mean there are at least two vtables instead of one.
Your original claim was just 'double' not 'double in the worst case'... Furthermore, your 'worst' case (where you only store one type) is actually a 'no use case'/antipattern as you yourself actually claim in this post http://lists.boost.org/Archives/boost/2010/11/172798.php concluding to the effect that this case is not something worth considering... Finally, for the umpteenth time, there are not at least two vtables instead of one:
- the problem with your implementation is that you copied the original assign() member function for your new "empty target" function copying with it the local static vtable...to do it right the vtable must not be a local (template) function static...
It doesn't matter whether the empty static assignment is in a different member function or not. boost::function will still require two static assignments: one for the actual target and one for the empty target.
No we do not, as I already explained in more detail and as pointed out by Peter Dimov (and maybe others)...will you please stop reasserting this false claim? This is what your 'wrong' implementation does/causes because it has two member functions with local static vtables...In the original implementation, and somewhat similarly in mine, there is one member function template with a local static vtable that depends (through the template parameters) on the type/signature of the boost::function<> and on the type of the assigned target...from this alone it directly follows that for targets of same type assigned to objects of one boost::function<> instantiation only a single vtable will be used...or IOW if the type of the empty target coincides with the type of any other target assigned to an object of the same instantiation _no_ additional vtable will be generated... QeD If you still don't believe fix your implementation and/or examine the binary generated for Peter Dimov's example and see for yourself...
Not to mention, as also already explained in more detail (and pointed to by Nevin), this 'overhead' of a few static pointers is completely insignificant compared to various related code bloat issues...
On some platforms the overhead of a few static pointers matters a great deal. Regardless, there's no reason to increase the static space overhead at all, if it does not improve time performance commensurately.
Right, except that arguing about the overhead of a few (const) static pointers w/o also mentioning the reduction in total time _and_ space overhead that this much smaller overhead enables is a straw man argument... Just as the implication that there is no time performance gain is simply false (as shown in the last post)... For example, the fact that the vtable in my implementation is ~3 times larger than the original matters hardly anything if it helps to save the equivalent of say 50 vtables in code size on each assignment (as demonstrated in the post linked to above or also here http://lists.boost.org/Archives/boost/2010/11/172682.php)... "if ( empty() ) push-something-on-the-stack" can generate larger code (replicated on every place it is inlined) than the size of one vtable...not to mention the real if ( empty() ) do-all-of-the-boost-exception-magic code... Even a call to the boost::function<> safe_bool operator on MSVC 9 or earlier will probably generate larger code than a vtable... ... -- "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:AANLkTi=Z=OtSBViFViTpkeZO4Un4yzvLuSuvXRysaBc-@mail.gmail.com...
On Tue, Oct 19, 2010 at 12:34 AM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Emil Dotchevski" <emil@revergestudios.com> wrote in message news:AANLkTi=1J3+hD0Oh3Le+6-jfnwDLYpTn_A7a6x=oZFnz@mail.gmail.com...
... at worst they'd be mad that you've used Boost (that's common in games, for example.)
Shall we disregard all those cases (of Boost rejection) as irrational rants (as admittedly they often are, be it of the 'corporate policy' type or of the Linus Torvalds type) or shall it be admitted that after all, sometimes, they actually are based on real objections (that Boost, or parts of it, made some not-so-happy efficiency compromising choices)...?
You can't talk about Boost efficiency in general.
I wasn't ("...or parts of it...")...
Are we talking about the efficiency of Boost Function then? I'm sure if someone manages to speed it up, many people on this mailing list (not to mention the folks who are implementing std::function) would be very interested to see how it can be done.
I'm sorry but what else have we been talking about in all these countless boost::function discussions? I have written pages and pages of not only what can be changed but of what I have changed...As mentioned in this old post http://lists.boost.org/Archives/boost/2010/01/160908.php I have managed to get a ~10% speedup with changes that are purely internal, that is they _do not_ change the interface or the semantics of boost::function...An additional ~10% was gained by turning on the nothrow policy (where a boost::function marks itself as nothrow)...this change obviously requires a break in the interface (with an additional template parameter)..... I've brought this up many times and it only received interest from Boost users, library author(s) did not seem to be even slightly, much less very, interested... And I am/was not alone, there have been others proposing (and implementing) various changes...but boost::function remained 'rock solid'... -- "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 12, 2010 at 7:59 PM, Peter Dimov <pdimov@pdimov.com> wrote:
Daniel Walker wrote:
But the coupling with Boost.Exception is only there to implement the strong exception safety guarantee of operator().
Your terminology is wrong. Both variants of operator() have the same exception safety; and even if they didn't, nobody uses "strong exception safety" to mean "throws an exception when such-and-so".
OK, I think there is a terminology problem here. I think we need to make a distinction between an "exception safety precondition" and a "call precondition" with respect to functions. A call precondition is a condition that must be met in order to call a function. An exception safety precondition is a condition that must be met in order to ensure that after a function has been called, during its execution, it conforms to an exception safety guarantee. Part of the requirements of boost::function is to account for differences between function pointers and function objects. A function object has no call precondition; i.e. a call to operator() cause operator() to execute. A function pointer does have a call precondition; i.e. a call to a function pointer only executes a function if the pointer is not null. In "promoting" function pointers to function objects, boost::function must transfer the call precondition from function pointers. To do this in an exception safe way, it must check whether the call precondition is met, otherwise it cannot offer a strong exception safety guarantee during the execution of boost::function::operator(). So, boost::function's precondition corresponds to a call precondition not an exception safety precondition. boost::function is always strong exception safe; i.e. boost::function invocation has no exception safety precondition. There are then two ways of looking at unsafe_function. You can say that it does not transfer the call precondition of function pointers in an exception safe way. Or you can say that it transfers the call precondition by making it an exception safety precondition, in which case unsafe_function is actually strong exception safe given the call precondition. So, using terminology that hopefully everyone can agree to, we can say that boost::function has no exception safety precondition (it is unconditionally strong exception safe), but with unsafe_function, the call precondition is an exception safety precondition.
The issue is not coupling with Boost.Exception, the issue is that the user has to supply a definition of boost::throw_exception when exceptions are disabled. This was true before there were Boost.Exception.
Well, I mean currently boost::throw_exception is part of Boost.Exception. So currently, from a user's perspective at least, boost::function is coupled with Boost.Exception. Daniel Walker

On Wed, Oct 13, 2010 at 9:41 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
In "promoting" function pointers to function objects, boost::function must transfer the call precondition from function pointers. To do this in an exception safe way, it must check whether the call precondition is met, otherwise it cannot offer a strong exception safety guarantee during the execution of boost::function::operator().
What Peter said: your terminology is wrong. Operator() of boost::function has basic (not strong) exception safety guarantee and this is true regardless of whether it wraps a function pointer or another callable object. Basic exception safety guarantee means that *if* an exception is emitted as a result of calling boost::function::operator(), the state of the program may be altered but no resources will leak. Whether or not an exception is emitted has nothing to do with exception safety. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Wed, Oct 13, 2010 at 1:31 PM, Emil Dotchevski <emil@revergestudios.com> wrote:
On Wed, Oct 13, 2010 at 9:41 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
In "promoting" function pointers to function objects, boost::function must transfer the call precondition from function pointers. To do this in an exception safe way, it must check whether the call precondition is met, otherwise it cannot offer a strong exception safety guarantee during the execution of boost::function::operator().
What Peter said: your terminology is wrong.
Operator() of boost::function has basic (not strong) exception safety guarantee and this is true regardless of whether it wraps a function pointer or another callable object.
If the call precondition is not met and boost::function::operator() attempts to call the target function, then the program could crash. Instead, under the current implementation, boost::function::operator() checks the call precondition and either completes successfully or throws an exception with the program state maintained, which conforms to our running definition of a strong exception safety guarantee.
Basic exception safety guarantee means that *if* an exception is emitted as a result of calling boost::function::operator(), the state of the program may be altered but no resources will leak. Whether or not an exception is emitted has nothing to do with exception safety.
boost::function::operator() offers a stronger guarantee than that: it either completes successfully or emits an exception, leaving the program state unaltered. Again, there is a nuance here in that the exact behavior of a boost::function invocation depends on the target function. So more formally, boost::function invocation is strong exception safe if the target function invocation is strong exception safe. Daniel Walker

On 13 October 2010 15:35, Daniel Walker <daniel.j.walker@gmail.com> wrote:
If the call precondition is not met and boost::function::operator() attempts to call the target function, then the program could crash.
In the case of raw function pointers (either NULL or uninitialized), from that point on the program can do whatever the heck it wants to do, since it is now in the realm of undefined behavior. Heck, you can no longer guarantee that *any* object in your system is still in a consistent, let alone correct state.
Instead, under the current implementation, boost::function::operator() checks the call precondition
What call precondition? It is perfectly legitimate to call operator() on a default constructed boost::function; it has well defined semantics. Now in your new class you want to change those well defined semantics into undefined behavior. But "undefined behavior" means that the program can do whatever the heck it wants, including the currently defined behavior for calling operator() on a default constructed boost::function. For a parallel, look at std::vector at() vs. operator[]. at() has no precondition on the index passed to it, while operator[] requires it to be in the range [0..size()). Would you say that operator[] doesn't have the strong exception safety guarantee?
and either completes successfully or throws an exception with the program state maintained, which conforms to our running definition of a strong exception safety guarantee.
Exception safety is an orthogonal issue, as you are talking about changing well defined semantics into undefined behavior. Undefined behavior in and of itself just isn't a motivation for any feature. And you aren't (just) relaxing the exception safety guarantees; rather, you are throwing them (as well as any other guarantees) out by invoking undefined behavior. -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404

On Wed, Oct 13, 2010 at 5:57 PM, Nevin Liber <nevin@eviloverlord.com> wrote:
On 13 October 2010 15:35, Daniel Walker <daniel.j.walker@gmail.com> wrote:
If the call precondition is not met and boost::function::operator() attempts to call the target function, then the program could crash.
In the case of raw function pointers (either NULL or uninitialized), from that point on the program can do whatever the heck it wants to do, since it is now in the realm of undefined behavior. Heck, you can no longer guarantee that *any* object in your system is still in a consistent, let alone correct state.
True, and in the worst case scenario, the program could crash.
Instead, under the current implementation, boost::function::operator() checks the call precondition
What call precondition? It is perfectly legitimate to call operator() on a default constructed boost::function; it has well defined semantics.
In order to call a function using boost::function, the following precondition must be met: boost::function must be non-empty. The reason that operator() has well defined semantics, even when called on a default constructed boost::function, is that operator() checks the call precondition before attempting to dispatch a target function.
Now in your new class you want to change those well defined semantics into undefined behavior. But "undefined behavior" means that the program can do whatever the heck it wants, including the currently defined behavior for calling operator() on a default constructed boost::function.
From the implementers point of view, yes, "undefined behavior" means
that the program could be given any particular behavior. But from the users' point of view, "undefined behavior" means that no particular behavior can be relied upon; i.e. there is no contract between the implementer and user as to how the function behaves. I think I should have emphasized earlier that unsafe_function is not "unsafe" in general, but is only unsafe relative to boost::function; i.e. given the same exception safety preconditions, the two do not have the same exception safety guarantee. However, given that the call precondition is met, i.e. the function wrapper is non-empty, then both are strong exception safe. I'm going to update the user documentation to make sure this is clear. BTW, I think some people don't like the name "unsafe," but I still prefer it. I think it's important to emphasis the distinction between the two wrappers. boost::function behaves as one might expect a function object to behave: invoking the target function happens seamlessly without requiring the user to become familiar with any new exception safety preconditions above and beyond the target function's preconditions. However, unsafe_function, under the same exception safety preconditions, does not behave the same way, and using it naively could cause an abrupt system failure. So, following the principle of least astonishment, I like the name unsafe_function as a warning to the user to be aware of the different exception safety preconditions of the two wrappers.
For a parallel, look at std::vector at() vs. operator[]. at() has no precondition on the index passed to it, while operator[] requires it to be in the range [0..size()).
Would you say that operator[] doesn't have the strong exception safety guarantee?
On the precondition that the vector is not empty, then operator[] has a strong exception safety guarantee. On the other hand, at() is unconditionally strong exception safe. It's just a matter of stating what the preconditions are for exception safety. boost::function has no exception safety precondition, unsafe_function has one exception safety precondition -- the call precondition.
and either completes successfully or throws an exception with the program state maintained, which conforms to our running definition of a strong exception safety guarantee.
Exception safety is an orthogonal issue, as you are talking about changing well defined semantics into undefined behavior. Undefined behavior in and of itself just isn't a motivation for any feature. And you aren't (just) relaxing the exception safety guarantees; rather, you are throwing them (as well as any other guarantees) out by invoking undefined behavior.
Undefined behavior is not the motivation. Actually, maybe it's a good idea to walk through how I arrived at this function wrapper to begin with, step-by-step. 1) The motivation is to remove the call to boost::throw_exception in operator(). 2) If boost::throw_exception is never used, then there's no reason to check the call precondition in operator(). In fact, the user request specifically emphasized that the empty check was unnecessary. 3) If you remove the empty check from operator(), how would you describe the resulting function's behavior to the user? Well, the behavior cannot always be defined, since it sometimes involves dereferencing a null pointer. Moreover, given the same exception safety preconditions as boost::function, it does not conform to the definition of basic, strong or nothrow exception safety. So, the resulting operator() is exception unsafe under the same exception safety preconditions as boost::function. 4) Hey, that's a good name! I'll call it unsafe_function. Daniel Walker

Daniel Walker wrote:
Nevin Liber wrote:
Daniel Walker wrote:
If the call precondition is not met and boost::function::operator() attempts to call the target function, then the program could crash.
In the case of raw function pointers (either NULL or uninitialized), from that point on the program can do whatever the heck it wants to do, since it is now in the realm of undefined behavior. Heck, you can no longer guarantee that *any* object in your system is still in a consistent, let alone correct state.
True, and in the worst case scenario, the program could crash.
No. The worst case scenario is that the program continues to run and does all sorts of wrong things like sending market orders for too many stocks at an enormous price or overdoses a patient.
Instead, under the current implementation, boost::function::operator() checks the call precondition
What call precondition? It is perfectly legitimate to call operator() on a default constructed boost::function; it has well defined semantics.
In order to call a function using boost::function, the following precondition must be met: boost::function must be non-empty. The
Not true. That is not a precondition. In order to successfully invoke a function, there must be a function to invoke, but boost::function's function call operator behaves as documented when there is no function. By contrast, a precondition is a condition that the caller must satisfy in order for the called function to behave as documented. Violating the precondition leaves the function's behavior wide open.
reason that operator() has well defined semantics, even when called on a default constructed boost::function, is that operator() checks the call precondition before attempting to dispatch a target function.
That is a case of behaving as documented. The operator is *not* checking a precondition. It is merely deciding which of two alternatives to pursue based upon the state of the object.
For a parallel, look at std::vector at() vs. operator[]. at() has no precondition on the index passed to it, while operator[] requires it to be in the range [0..size()).
Would you say that operator[] doesn't have the strong exception safety guarantee?
On the precondition that the vector is not empty, then operator[] has a strong exception safety guarantee. On the other hand, at() is unconditionally strong exception safe. It's just a matter of stating what the preconditions are for exception safety. boost::function has no exception safety precondition, unsafe_function has one exception safety precondition -- the call precondition.
That isn't an "exception safety precondition" as you call it. It is a precondition. If you call a function without satisfying its preconditions, the function can behave in any way. The caller violated the precondition so the function is not obligated to behave in any rational manner, much less in keeping with its documentation. If the caller satisfies the precondition, then the function is obligated to behave as documented, including meeting any documented exception guarantee. In the case of Boost.Function, it's:
either completes successfully or throws an exception with the program state maintained, which conforms to our running definition of a strong exception safety guarantee.
I hope this helps, at least by clarifying terminology. _____ 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 21, 2010 at 7:33 AM, Stewart, Robert <Robert.Stewart@sig.com> wrote:
Daniel Walker wrote:
Nevin Liber wrote:
Daniel Walker wrote:
If the call precondition is not met and boost::function::operator() attempts to call the target function, then the program could crash.
In the case of raw function pointers (either NULL or uninitialized), from that point on the program can do whatever the heck it wants to do, since it is now in the realm of undefined behavior. Heck, you can no longer guarantee that *any* object in your system is still in a consistent, let alone correct state.
True, and in the worst case scenario, the program could crash.
No. The worst case scenario is that the program continues to run and does all sorts of wrong things like sending market orders for too many stocks at an enormous price or overdoses a patient.
Oh man. That would be awful!
Instead, under the current implementation, boost::function::operator() checks the call precondition
What call precondition? It is perfectly legitimate to call operator() on a default constructed boost::function; it has well defined semantics.
In order to call a function using boost::function, the following precondition must be met: boost::function must be non-empty. The
Not true. That is not a precondition. In order to successfully invoke a function, there must be a function to invoke, but boost::function's function call operator behaves as documented when there is no function.
By contrast, a precondition is a condition that the caller must satisfy in order for the called function to behave as documented. Violating the precondition leaves the function's behavior wide open.
I think in the case of function wrappers it helps to make a distinction between what I call a "call precondition" and an "exception safety precondition." A call precondition is a condition that must be met in order to invoke a function. One example would be, as you put it, "there must be a function to invoke;" i.e. the wrapper has to be assigned a target. Here's another example: Imagine we had a remote function wrapper so that remote function calls could be used interchangeable with other wrapped functions. Then a call precondition of the remote function wrapper would be that the remote host is available. Or here's a simpler example: if you intend to invoke a function through a function pointer, a call precondition is that the function pointer is not null. An exception safety precondition applies after a function has been called and is running. And I like your wording, it is "a condition that the caller must satisfy in order for the called function to behave as documented" with respect to exception safety. I think the reason the distinction is important is that function objects do not normally have call preconditions; i.e. the function is always there, and when operator() is invoked, control is passed to the function. With function wrappers, however, there is a level of indirection. When a function wrapper is invoked, control is not instantly passed to the wrapped function. This gives rise to some trade-offs. With boost::function, the call precondition is handled transparently with respect to strong exception safety such that calling a wrapped function is the same as calling the function directly: Either an exception will be thrown or the function will complete successfully given the target function's exception safety preconditions. With unsafe_function, the call precondition is an _additional_ exception safety precondition, and so, unlike boost::function, its behavior is not documented (or defined) when the call precondition is not met.
<snip> I hope this helps, at least by clarifying terminology.
Yes, thanks, I think it does help. You're using the term "precondition" in a broad sense, which is perfectly fine. But I think making a distinction between a condition needed to invoke a function and a condition needed while running a function helps when discussing the difference between boost::function and unsafe_function. boost::function and unsafe_function have different "preconditions" in the broad sense (they have different exception safety preconditions, I would say), but they have the same call precondition -- a condition that must be met to actually invoke a target function. Daniel Walker

On Thu, Oct 21, 2010 at 5:32 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
I think in the case of function wrappers it helps to make a distinction between what I call a "call precondition" and an "exception safety precondition." A call precondition is a condition that must be met in order to invoke a function. One example would be, as you put it, "there must be a function to invoke;" i.e. the wrapper has to be assigned a target. Here's another example: Imagine we had a remote function wrapper so that remote function calls could be used interchangeable with other wrapped functions. Then a call precondition of the remote function wrapper would be that the remote host is available.
Assuming the remote host could disappear at any moment, this is a bad example of precondition because the caller can not guarantee that the host will be there by the time the function executes and completes. This works well for postcondition example: the postcondition would be that if the function returns then the remote host was available and performed the task successfully (otherwise you'd get an exception.)
An exception safety precondition applies after a function has been called and is running. And I like your wording, it is "a condition that the caller must satisfy in order for the called function to behave as documented" with respect to exception safety.
If the caller violates a precondition, all bets are off not only wrt exception safety (the plane may crash, the patient may overdose.)
I think the reason the distinction is important is that function objects do not normally have call preconditions; i.e. the function is always there, and when operator() is invoked, control is passed to the function.
The function you point to may still have its own preconditions. It isn't a good idea to pass control to a function, through a pointer or otherwise, unless its preconditions are met.
With boost::function, the call precondition is handled transparently with respect to strong exception safety such that calling a wrapped function is the same as calling the function directly: Either an exception will be thrown or the function will complete successfully
...unless the preconditions of the target function aren't met, in which case the plane crashes, the patient is overdosed, AKA undefined behavior.
I hope this helps, at least by clarifying terminology.
Yes, thanks, I think it does help. You're using the term "precondition" in a broad sense
He is using the term precondition as it is used by everyone. Your terminology appears to be wrong: what you mean by preconditions and exception safety doesn't seem to be what everyone means by those terms. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

Emil Dotchevski wrote:
On Thu, Oct 21, 2010 at 5:32 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
I think in the case of function wrappers it helps to make a distinction between what I call a "call precondition" and an "exception safety precondition." A call precondition is a condition that must be met in order to invoke a function. One example would be, as you put it, "there must be a function to invoke;" i.e. the wrapper has to be assigned a target. Here's another example: Imagine we had a remote function wrapper so that remote function calls could be used interchangeable with other wrapped functions. Then a call precondition of the remote function wrapper would be that the remote host is available.
Assuming the remote host could disappear at any moment, this is a bad example of precondition because the caller can not guarantee that the host will be there by the time the function executes and completes.
+1
This works well for postcondition example: the postcondition would be that if the function returns then the remote host was available and performed the task successfully (otherwise you'd get an exception.)
Exactly. Such a function must account for the variable conditions necessary for it to complete successfully. The network could be down. There could be no route to the remote host. The remote host could be down. The remote host could be slow to respond. All of these can lead to a failure that the caller shouldn't be responsible to ensure before being allowed to call the wrapper. They are runtime conditions the wrapper must handle. Handling might mean retrying some number of times and then, ultimately returning an error code or throwing an exception.
An exception safety precondition applies after a function has been called and is running. And I like your wording, it is "a condition that the caller must satisfy in order for the called function to behave as documented" with respect to exception safety.
If the caller violates a precondition, all bets are off not only wrt exception safety (the plane may crash, the patient may overdose.)
Right. If the caller didn't establish necessary conditions for calling the function, then the function is not responsible for the results. OTOH, if the caller does meet the preconditions, *everything* else is the responsibility of the called function WRT to documented behavior, including exception guarantees. In the case of boost::function, having no target *is* a valid state. Therefore, the function call operator *must* account for that state. It does so by throwing an exception. There is no precondition violation when there is no target.
I think the reason the distinction is important is that function objects do not normally have call preconditions; i.e. the function is always there, and when operator() is invoked, control is passed to the function.
The function you point to may still have its own preconditions. It isn't a good idea to pass control to a function, through a pointer or otherwise, unless its preconditions are met.
+1 _____ 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.

Daniel Walker wrote:
Rob Stewart wrote:
By contrast, a precondition is a condition that the caller must satisfy in order for the called function to behave as documented. Violating the precondition leaves the function's behavior wide open.
I think in the case of function wrappers it helps to make a distinction between what I call a "call precondition" and an "exception safety precondition." A call precondition is a condition that must be met in order to invoke a function. One example would be, as you put it, "there must be a function to invoke;" i.e. the wrapper has to be assigned a target.
That example is valid only if the design and documentation of the wrapper establish that as a precondition. It does not apply to boost::function.
Or here's a simpler example: if you intend to invoke a function through a function pointer, a call precondition is that the function pointer is not null.
Yes. That precondition is given by the language. Violating it results in UB.
An exception safety precondition applies after a function has been called and is running. And I like your wording, it is "a condition that the caller must satisfy in order for the called function to behave as documented" with respect to exception safety.
If the caller must establish that condition before invoking the function, then it is a precondition, pure and simple. Violating a precondition leaves the result wide open. In the case of boost::function, there is no such precondition. If invoked without a target, boost::function throws an exception. There's nothing special in that. It is documented behavior. The caller met the preconditions, invoked the boost::function object, that object found no target, and it threw an exception, all as expected.
I think the reason the distinction is important is that function objects do not normally have call preconditions; i.e. the function is always there, and when operator() is invoked, control is passed to the function.
This is the case for boost::function except that there's an additional state permitted: the target may not exist and the result is an exception.
With function wrappers, however, there is a level of indirection. When a function wrapper is invoked, control is not instantly passed to the wrapped function. This gives rise to some trade-offs. With boost::function, the call precondition is handled transparently with respect to strong exception safety such that calling a wrapped function is the same as calling the function directly: Either an exception will be thrown or the function will complete successfully given the target function's exception safety preconditions.
I hope Emil and I have helped you to understand that this is simply wrong. boost::function will throw an exception due to no target, or will invoke the target. There is nothing special in that and no precondition applies. What happens upon calling the target is the responsibility of boost::function's caller and the target; it is no different than invoking the target directly.
With unsafe_function, the call precondition is an _additional_ exception safety precondition, and so, unlike boost::function, its behavior is not documented (or defined) when the call precondition is not met.
unsafe_function's function call operator has a precondition that the target exists. Calling it without a target results in UB. Nothing else matters after that. The distinction between boost::function and unsafe_function is that the latter's function call operator has a precondition that the target exists while the former's doesn't. _____ 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 Dimov" <pdimov@pdimov.com> wrote in message news:C08645771EF04EAEBD9230358B35BDFB@pdimov5...
David Abrahams wrote:
Is *that* the core issue here? Because it seems like the issue has been about various other things earlier in this conversation.
The core issue, if I remember correctly, is that when a library uses boost::function internally without ever calling it while NULL and the user compiles with exceptions disabled, he needs to supply a definition of boost::throw_exception even though it will never be called.
IMO, if we try to look at this discussion in the context of all the other boost::function related discussions and all the various alternative implementations that circulate around the internet, the core issues jump right out: it is always about inefficiency and/or lack of configurability... Considering that those issues are consistently brought up every once in a while, the question that logically follows is why do we still have the boost::function implementation that we do? After all, a fraction of the effort spend in these run-around-in-circles discussions would have been enough to make relevant changes to boost::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

On Tue, Oct 19, 2010 at 12:32 AM, Domagoj Saric <dsaritz@gmail.com> wrote:
"Peter Dimov" <pdimov@pdimov.com> wrote in message news:C08645771EF04EAEBD9230358B35BDFB@pdimov5...
David Abrahams wrote:
Is *that* the core issue here? Because it seems like the issue has been about various other things earlier in this conversation.
The core issue, if I remember correctly, is that when a library uses boost::function internally without ever calling it while NULL and the user compiles with exceptions disabled, he needs to supply a definition of boost::throw_exception even though it will never be called.
IMO, if we try to look at this discussion in the context of all the other boost::function related discussions and all the various alternative implementations that circulate around the internet, the core issues jump right out: it is always about inefficiency and/or lack of configurability... Considering that those issues are consistently brought up every once in a while, the question that logically follows is why do we still have the boost::function implementation that we do? After all, a fraction of the effort spend in these run-around-in-circles discussions would have been enough to make relevant changes to boost::function...
Even if there were sufficient demand to change boost::function, that's not how Boost works. Each Boost library has a maintainer and once the library is accepted, (s)he needs to be sold on the change. There's also the issue that it seems a good idea to keep boost::function unchanged so it doesn't deviate from std::function. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On 19/10/10 09:56, Emil Dotchevski wrote:
Even if there were sufficient demand to change boost::function, that's not how Boost works. Each Boost library has a maintainer and once the library is accepted, (s)he needs to be sold on the change.
There's also the issue that it seems a good idea to keep boost::function unchanged so it doesn't deviate from std::function.
can't we resort to an artifice like function2, much like signal and signal2 coexists ?

----- Original Message ----- From: "Joel Falcou" <joel.falcou@lri.fr> To: <boost@lists.boost.org> Sent: Tuesday, October 19, 2010 10:06 AM Subject: Re: [boost] [function] function wrapping with noexception safetyguarantee
On 19/10/10 09:56, Emil Dotchevski wrote:
Even if there were sufficient demand to change boost::function, that's not how Boost works. Each Boost library has a maintainer and once the library is accepted, (s)he needs to be sold on the change.
There's also the issue that it seems a good idea to keep boost::function unchanged so it doesn't deviate from std::function.
can't we resort to an artifice like function2, much like signal and signal2 coexists ?
+1, but we need someone to do the work :( Best, Vicente

On Tue, Oct 19, 2010 at 3:03 PM, vicente.botet <vicente.botet@wanadoo.fr> wrote:
----- Original Message ----- From: "Joel Falcou" <joel.falcou@lri.fr> To: <boost@lists.boost.org> Sent: Tuesday, October 19, 2010 10:06 AM Subject: Re: [boost] [function] function wrapping with noexception safetyguarantee
On 19/10/10 09:56, Emil Dotchevski wrote:
Even if there were sufficient demand to change boost::function, that's not how Boost works. Each Boost library has a maintainer and once the library is accepted, (s)he needs to be sold on the change.
There's also the issue that it seems a good idea to keep boost::function unchanged so it doesn't deviate from std::function.
can't we resort to an artifice like function2, much like signal and signal2 coexists ?
+1, but we need someone to do the work :(
What's the benefit of function2 vs. adding a nothrow_t constructor to function? Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

----- Original Message ----- From: "Emil Dotchevski" <emil@revergestudios.com> To: <boost@lists.boost.org> Sent: Wednesday, October 20, 2010 12:06 AM Subject: Re: [boost] [function] function wrapping with noexceptionsafetyguarantee
On Tue, Oct 19, 2010 at 3:03 PM, vicente.botet <vicente.botet@wanadoo.fr> wrote:
----- Original Message ----- From: "Joel Falcou" <joel.falcou@lri.fr> To: <boost@lists.boost.org> Sent: Tuesday, October 19, 2010 10:06 AM Subject: Re: [boost] [function] function wrapping with noexception safetyguarantee
On 19/10/10 09:56, Emil Dotchevski wrote:
Even if there were sufficient demand to change boost::function, that's not how Boost works. Each Boost library has a maintainer and once the library is accepted, (s)he needs to be sold on the change.
There's also the issue that it seems a good idea to keep boost::function unchanged so it doesn't deviate from std::function.
can't we resort to an artifice like function2, much like signal and signal2 coexists ?
+1, but we need someone to do the work :(
What's the benefit of function2 vs. adding a nothrow_t constructor to function?
I have not followed all the change request to boost::function but it seems to me that not all are compatible with the current interface. So my opinion is that the people that are interested in the change make a conrete proposal in the form of a new library or a library extension and we will see if the proposal is accepted by the Boost community. Change requests that break the interface should not be acceptable in principle. Just my opinion, Vicente

On Tue, Oct 19, 2010 at 6:20 PM, vicente.botet <vicente.botet@wanadoo.fr> wrote:
----- Original Message ----- From: "Emil Dotchevski" <emil@revergestudios.com> To: <boost@lists.boost.org> Sent: Wednesday, October 20, 2010 12:06 AM Subject: Re: [boost] [function] function wrapping with noexceptionsafetyguarantee
On Tue, Oct 19, 2010 at 3:03 PM, vicente.botet <vicente.botet@wanadoo.fr> wrote:
----- Original Message ----- From: "Joel Falcou" <joel.falcou@lri.fr> To: <boost@lists.boost.org> Sent: Tuesday, October 19, 2010 10:06 AM Subject: Re: [boost] [function] function wrapping with noexception safetyguarantee
On 19/10/10 09:56, Emil Dotchevski wrote:
Even if there were sufficient demand to change boost::function, that's not how Boost works. Each Boost library has a maintainer and once the library is accepted, (s)he needs to be sold on the change.
There's also the issue that it seems a good idea to keep boost::function unchanged so it doesn't deviate from std::function.
can't we resort to an artifice like function2, much like signal and signal2 coexists ?
+1, but we need someone to do the work :(
What's the benefit of function2 vs. adding a nothrow_t constructor to function?
I have not followed all the change request to boost::function but it seems to me that not all are compatible with the current interface. So my opinion is that the people that are interested in the change make a conrete proposal in the form of a new library or a library extension and we will see if the proposal is accepted by the Boost community.
Change requests that break the interface should not be acceptable in principle.
FYI, there is already a boost::function2. It's a portable, binary function wrapper that works on compilers without partial specialization. http://www.boost.org/doc/libs/1_44_0/doc/html/boost/functionN.html#id1273294 However, I do agree that the best solution is to leave boost::function as is and provide an alternative function wrapper with alternative semantics. unsafe_function is a simple way to do that. Daniel Walker

"vicente.botet" <vicente.botet@wanadoo.fr> wrote in message news:C760054B35E448C8A31F88FED992010A@viboes1...
Change requests that break the interface should not be acceptable in principle.
True, but in itself this practically a tautology... Obviously, and thankfully, it is also not a dogma as sometimes other goals have outweighed this principle (so we did have breaking changes, like the Filesystem, GIL.IO....)... -- "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:AANLkTi=538M7U-njGg+jXZ75kLy7Qtx3_U+Nw_WOkr7d@mail.gmail.com...
What's the benefit of function2 vs. adding a nothrow_t constructor to function?
What's so different between adding more overloads to boost::function constructors and assignment operators and adding more defaulted template parameters? How would you, for example, make a boost::function<> use a non-default SBO size or mark itself as nothrow using more runtime constructor parameters? -- "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:AANLkTi==wpp=53+4YEHUrfV+Wk_Z15D1GQzvgyhW87Rb@mail.gmail.com...
Even if there were sufficient demand to change boost::function, that's not how Boost works. Each Boost library has a maintainer and once the library is accepted, (s)he needs to be sold on the change.
I know that, and those that want the change then have no other 'democratic' option but to repeatedly ask for/propose changes (or whine, depending on the perspective)... However, it would polite of a library author(s) to at least respond in a sensible way to discussions about their own library, especially when they go on for years... If one is unable to write a post about one's own library every few months much less maintain it (especially if its a core library) transfer of ownership (even if temporary) becomes a viable option...
There's also the issue that it seems a good idea to keep boost::function unchanged so it doesn't deviate from std::function.
The measure of 'goodness' of that idea is a matter of a cost-benefit analysis as well as, obviously, a matter of taste as I have argued in another post...Where I've also noted that it can actually be both ways...just like Joel propsed... -- "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 Thu, Oct 7, 2010 at 10:44 PM, Bryce Lelbach <admin@thefireflyproject.us> wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
I think this is great, for selfish reasons. I'm currently working on a project that uses the clang and LLVM API. clang and LLVM coding conventions are to compile w/o exceptions and without RTTI. I'm able to compile the Boost that I use (Spirit/Proto/Fusion + deps mostly) without RTTI (after a minor fix to the provided Boost workaround), but getting jazz to compile without exceptions is a larger task. This would make it easier.
clang and LLVM do not use exceptions and RTTI because they found that compiling without these two features decreases binary size and increased runtime speed. Given how popular clang and LLVM are, I think any changes that Boost can make to reduce RTTI/exception dependencies without decreasing the functionality or portability of Boost would be good for adoption.
I think the impact of exceptions on efficiency may vary from application to application and certainly depends on the compiler's optimization. (In optimized object code unsafe_function does not seem to be significantly more efficient than boost::function.) But yes, if your project finds it is best to work without RTTI then boost::function's exception safety guarantee will get in the way, and it would be nice to have a function wrapper with no exception safety guarantee. Daniel Walker

On Thu, Oct 7, 2010 at 9:22 PM, Peter Dimov <pdimov@pdimov.com> wrote:
Daniel Walker wrote:
void do_stuff(boost::function<int(int)> f) { // ... if(f) { // Remove the exception safety guarantee for this block. boost::unsafe_function<int(int)> g = f; for(int i = 0; i < INT_MAX; ++i) g(i); } // ... }
This example implies that unsafe_function is inherently more efficient, but this need not be so. An empty function may point to throw_bad_function_call instead of NULL.
I don't believe efficiency is a significant issue. I tried to measure the difference in performance between boost::function and unsafe_function in a tight loop, and with gcc -02, the difference is on the order of hundreds of picoseconds; i.e. in optimized code on contemporary PC hardware, unsafe_function is not significantly more efficient. But of course, results will vary according to your optimizer. The main advantage I see in unsafe_function is that it could be useful in environments where throw_bad_function_call and/or compiler optimizations are unavailable, such as in some embedded systems. Daniel Walker
participants (19)
-
Bryce Lelbach
-
Daniel Walker
-
Dave Abrahams
-
David Abrahams
-
Domagoj Saric
-
Domagoj Saric
-
Doug Gregor
-
Edward Diener
-
Emil Dotchevski
-
Felipe Magno de Almeida
-
Jeff Flinn
-
Jeffrey Lee Hellrung, Jr.
-
Joel Falcou
-
Kazutoshi Satoda
-
Nevin Liber
-
OvermindDL1
-
Peter Dimov
-
Stewart, Robert
-
vicente.botet