Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2003-10-08 19:27:18


Brian McNamara <lorgon_at_[hidden]> writes:

> On Wed, Oct 08, 2003 at 07:27:43PM -0400, David Abrahams wrote:
>> Makes sense, but it seems like F(Y) could be equivalent to F[Y] where
>> Y is a lambda_arg.
> ...
>> which makes the F(Y) syntax not just viable, but desirable, it
>> seems to me.
>
> (I address your suggestion shortly, after a more general digression.)
>
> There are problems with the approach of just using operator(). The
> most convincing one, IMO, is that right now you can do
>
> int print_and_inc( int x ) {
> cout << x << endl;
> return x+1;
> }
> // now imagine "p_a_i" is the corresponding functoid
>
> // here is a nullary functoid which prints 3 and returns 4 when
> // invoked:
> lambda()[ p_a_i[3] ]
>
> If you eliminate operator[] and overload operator() to take on both
> semantics, you can no longer easily "delay side effects" using lambda:
>
> // Whoops, prints now, rather than later when someone invokes it.
> lambda()[ p_a_i(3) ]

I wasn't suggesting eliminating []. Of course, Boost.Lambda uses
constant(3) to achieve the same thing, but I like the terseness of [].
The real problem is, you give up a lot of readability by having to
write %plus% instead of +.

> As you say, you could have f(Y) mean f[Y] *iff Y is a lambda_var*. But
> then this starts to interfere with other things. For example, the
> identity function "id" always returns its argument unchanged. You can
> replace any expression "expr" with "id(expr)" without changing the
> semantics of your program. Thus, currently,
>
> // function to add one (also spelled "inc" or "plus(1)")
> lambda(X)[ plus[1,X] ]
>
> // equivalent
> lambda(X)[ plus[1,id(X)] ]
>
> But if you start overloading () for use with lambda, the "equivalent"
> code above breaks. (This example is a little contrived, but I do think
> more general examples along these lines may arise.)

No, I see. A little metaprogramming in the functional domain, anyone?
Being able to switch between eager and lazy evaluation at will has
some appeal... but if this is really functional land, everything
should be able to be lazy, right? I guess I want to see a
less-contrived example before I buy in fully.

> Finally, we like the explicitness of
>
> - if you call f with square brackets, the call gets delayed
> - if you call f with round brackets, the call happens now
>
> compared to approaches like
>
> - if you call f, and somewhere nested inside one of f's arguments is a
> lambda expression, then the call to f gets delayed, else the call
> happens now

MPL's lambda sort of works that way. It works well, but we have
fewer syntax options to work with.

> There are clearly trade-offs among all of the interesting points in the
> design space. Our goal was to try to choose the point which is least
> likely to cause accidents (where "accidents" means something like: your
> program compiles warning-free, but it exhibits behavior other than the
> one you intended).

Understood. It would be great if we could somehow separate interface
from implementation so people could choose where to be in the syntax
space choices without giving up the capabilities of FC++.

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk