|
Boost : |
From: Douglas Gregor (gregod_at_[hidden])
Date: 2002-04-16 23:15:34
On Tuesday 16 April 2002 10:23 pm, you wrote:
> I'll look into Loki's Functor vs. Boost.Function to see what features we
> might want to bring in.
I meant to do it 'later', but here's a comparison now. Disclaimer: I don't
have MC++D around, so my comments about Loki Functor are based on my reading
of the source code. I'll refer to Loki Functor and Boost.Function as
"function object wrappers" throughout.
In places where Loki Functor and Boost.Function disagree in semantics, usage,
features, etc., I'll outline the differences, weigh some options (IMHO!), and
given my proposed resolution (i.e., how should Boost.Function be changed?)
---------------------------------------------------------------------------
Issue: passing argument types to the function object wrapper
- Loki Functor: arguments are passed as a Loki typelist.
- Boost.Function: arguments are passed as individual template parameters.
- My opinion: both styles have merit. By passing a typelist containing the
template parameters, a lot of hackery that deals with the question "how many
arguments did the user pass?" disappears. For instance, the separation that
exists in Boost.Function between function0, function1, etc. disappears and
tricks such as the use of named template parameters in boost::function would
not be necessary. Additionally, this might make it easier to create the
appropriate function object wrapper types from a metaprogram when you don't
know the number of arguments in advance; however, I have never personally
needed this ability. Has anyone needed this ability?
On the flip side, I personally still prefer the individual template
parameters. They feel like a more obvious translation from function types to
function object wrapper types. Functor<void, TYPELIST_3(int, float, double)>
bothers me for some reason, and aesthetically I prefer Functor<void, int,
float, double> (this could be the bias of seeing the latter very often).
The situation would be much different for me if there were a direct
translation from a typelist facility to a function declaration/definition in
the language. For instance, if we were able to create a function like:
void foo(TYPELIST_4(int, float, double, std::string)) { /* ... */ }
and access the members of the typelist in some simple fashion at run-time,
then the idea of packaging all of the arguments in a typelist would be more
natural in C++. I think I would then support a changeover to that method.
- Proposed resolution: No change at this time.
---------------------------------------------------------------------------
Issue: parameter passing for forwarding functions
- Loki Functor: parameters are passed in an optimal way based on Loki's
type traits facility.
- Boost.Function: parameters are passed exactly as specified by the user.
- My opinion: this is the classic argument-forwarding problem coming back
to bite us yet again. Do we try to optimize (at the risk of changing the
semantics) or do we let the user decide (to possibly shoot herself in the
foot?). I chose the latter because of this:
Loki::Functor<std::string, TYPELIST_2(std::string, std::string)> f;
std::cout << f("hello ", "world\n");
This gives an error because std::string is passed-through as std::string&,
which can't be passed a temporary object. The equivalent Boost.Function code
(just change Loki::Functor to boost::function and drop the TYPELIST_2) would
compile and execute properly, but incur and additional string copy in the
middle.
My opinion is that the above code should be valid. Let the wary user
optimize, and be clear about what is going on, but don't optimize yourself.
- Proposed resolution: No change.
---------------------------------------------------------------------------
Issue: function object wrappers with a "void" return type
- Loki Functor: function objects targeted (called) by the wrapper must have
a void return type.
- Boost.Function: the return value of target function objects is ignored,
regardless of type.
- My opinion: the difference here is in the interpretation of 'void'. We
can interpret to mean "targets must have a void return value" or "the return
value is irrelevant". I favor the latter because it gives greater freedom in
the use of the function object wrappers, and because I believe it matches C++
semantics more closely. If I have a function 'f' that takes no arguments, I
can write:
f();
This will call the function. If there is a value returned, it is ignored;
if no value is returned, that's fine too. But if I have:
Loki::Functor<void> g = &f;
g();
This will not work if 'f' returns something other than void. This strikes
me as not being "in the spirit of the language" because we've restricted the
semantics unnecessarily.
- Proposed resolution: No change.
---------------------------------------------------------------------------
Issue: binding an object to a member function pointer
- Loki Functor: a constructor exists that takes a pointer to an object (or
anything that acts like a pointer) and a pointer-to-member-function and binds
the object pointer to the first argument of the member function pointer.
- Boost.Function: no equivalent.
- My opinion: we talked this one to death, repeatedly. I still think that
binding is out-of-scope for a function object wrapper library, because it
will inevitable be done better by another library (Bind, Lambda, Phoenix,
etc.).
- Proposed resolution: No change.
---------------------------------------------------------------------------
Issue: multithreading support
- Loki Functor: supports a multithreading policy.
- Boost.Function: no multithreading support.
- My opinion: Boost.Function needs multithreading support (as does most of
the rest of Boost).
- Proposed resolution: make Boost.Function parameterized based on a
multithreading policy. The form of this multithreading policy should be
discussed because it should be common across all of Boost.
---------------------------------------------------------------------------
Issue: function chaining
- Loki Functor: supports chaining of function objects (call first function
object, then second function object).
- Boost.Function: no equivalent.
- My opinion: useful tool, but it belongs in a functional composition
library and not in a function object wrapper.
- Proposed resolution: maybe add chain() to boost::functional?
I'll post more if I run across anything. Please feel free to append or
correct.
Doug
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk