|
Boost : |
From: Douglas Gregor (gregod_at_[hidden])
Date: 2001-06-14 07:02:30
On Thursday 14 June 2001 03:43, you wrote:
> > The problem is that a bind library tends to grow uncontrollably and
>
> since
>
> > the 'Bind' part of Lambda is scheduled right after the 'Tuple'
>
> part... you
>
> > get the idea. :-)
> >
> > Identifying a 'simple' bind subset isn't easy, since different
>
> people have
>
> > different needs.
>
> I agree with the uncontrollable growth. A code that performs the
> placeholder substitutions with function composition is already over
> 'simple'. And once that part is done, why not add binding of
> operators, and why not control structures ...
>
> We're cutting LL into smaller pieces. tuples became a separate library
> as it is really quite different concept of binding. It is just a tool
> that LL uses.
> bind wont't become another library, but rather the
> user include features like bind functions, operators, control
> structures separately, and each of these include the core machinery
> to make argument substitution and return type deduction work.
>
> Anyway, I like the idea of making LL and function work together.
> But if we take that step, why confine it to just bind invocations:
>
> If something like this would work:
>
> ostream& print(ostream& o, int i) { return o << i; }
> function<ostream&, int> outputter = bind(print, ref(cout), free1)
> // ref is to make bind store cout as reference
> outputter(1);
>
> why not:
>
> function<ostream&, int> outputter = (cout << free1)
> outputter(1);
It's all the same to Boost.Function.
> One detail that requires thinking is that LL stores some of the bound
> arguments as references.
> E.g. the function object resulting from a lambda expression
> a += free1 holds a reference to a.
> In current LL this is ok, as the function objects cannot really be
> stored for future use, but are constructed and evaluated at the same
> site.
> Now, if we store the function object into a variable,
> there's a fear for dangling references.
>
> int *a = new int();
> function<int&, int> f = (*a += free1);
> f(7); // ok
> delete a;
> f(7); // dangling reference
>
> Cheers, Jaakko
Boost.Function won't be dealing with this. However, I was going to bring up
the issue soon because a signals & slots library is on the horizon, and the
issue is pertinent there.
Signals & slots deals with the problem of dangling references, pointers, etc.
by removing connections when objects die. All of the signals & slots
libraries I've seen thus far include limited binder libraries (usually just
something that binds the "this" argument for a pointer-to-member-function)
and when "this" dies, the connection dies.
We don't want to do the same for Boost. Binding and deferred calls are
orthogonal concepts, even for signals & slots. So I need a way to
(statically) traverse all bound objects in a function object (and all
contained function objects, etc). Then I can find all objects that are able
to signal end-of-lifetime so that they can destroy the connection when they
are destroyed.
Here's a possible interface: the signals & slots library defines a visitor
class as such:
struct BindLifetimes {
void visit(slot_base& slot);
void visit(slot_base* slot);
template<typename T> visit(T); // some hook for user-defined pointer types
};
The lambda library (or binding library) defines a function that traverses all
bound objects:
template<typename LambdaFunction, typename Visitor>
inline void traverse_bound_objects(const LambdaFunction&, Visitor);
I need this sort of thing to make signals & slots work well, and of course
I'm willing to help out on the lambda end to get it done.
Doug
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk