Boost logo

Boost :

From: Brian McNamara (lorgon_at_[hidden])
Date: 2004-02-16 20:46:43


On Tue, Feb 17, 2004 at 08:54:25AM +0900, Darren Cook wrote:
> Thanks for the detailed reply Brian.

No problem; thanks for showing an interest in the library! :)

> >>1. (from the paper)
> >> int a[]={5,3,8,4};
> >> std::for_each(a,a+4,std::cout<<_1<<"\n");
> >
> >In FC++ it'd look like this:
> >
> > std::for_each(a,a+4,
> > lambda(X)[ &cout %out_stream% X %out_stream% '\n' ] );
>
> The use of X is just tradition is it? I could just as easily use _1, or
> some meaningful variable? Being able to name the variable is an advantage.

Yes; in the (previously) attached example you can see that you may name
it whatever you like.

> On the other hand %out_stream% is not as nice as <<. Is FC++ overloading
> operator<< an option? I think the "Hello World" examples have to be as
> attractive as possible to bring the punters in.

The paper "Syntax sugar for FC++: lambda, infix, monads, and more"
discusses a bit of the design rationale here, but here's a capsule
summary:
 - FC++ has "named functoids" for the operators, because these named
   entities can be used in lots of ways:
      plus(x,y)
      f(plus)
      3 ^plus^ 4
      plus[X,3]
      plus(1)
   You can't do all the same things with operators (like "+").

 - Overloaded operators do give you better lambda syntax, but sometimes
   at the cost of surprises, like this example
      int a[]={5,3,8,4};
      std::for_each(a,a+4,std::cout<<"v="<<_1<<"\n");
      // whoops, forgot constant(), does wrong thing

 - We overloaded operators as other kinds of syntax sugar (e.g. ^, %,
   and [] seen above).

Basically "we went a different way". There are some examples that are
shorter/simpler/easier/whatever with fcpp::lambda, and there are many
examples that are s/s/e/w with boost::lambda. Use the one that works
for you. (For the most part, the libraries should interoperate.)

> > lambda(X)[ &cout %out_stream% string("v=")
> > %out_stream% X %out_stream% '\n' ] );
> >
> >Same thing here, with the added annoyance that you have to manually turn
> >the string literal into some "by-value" type....
>
> But after reading your source I realized this is doing a different job to
> constant() in BLL isn't it. It is just the "..." string that is the
> problem, not that the lambda variable is not the first thing in the
> expression.

I'm not quite sure I understand your question, but:

 - In boost::lambda, you sometimes need constant() when the lambda
   variable isn't the first/deepest thing in the expression. In FC++,
   this is not an issue (or it is a different kind of issue, depending
   on how you view things) owing to the use of % and [] in lambda
   expressions.

 - In FC++, string literals never seem to work as parameters because the
   templates always infer their types as "array of const char", and
   arrays can't be "copied", or some such annoying thing. But string
   literals are an issue orthogonal to the evaluation order issue.

> I was hoping you might have some way to get rid of the "&MyClass::" bit, so
> I could write:
> lambda(test)[ test->save(f) ]

Nope. In fact, it's impossible to write a C++ library to let you do
that in general (that is, one that works for any member function).

> In most of my real code "MyClass" is actually a 60 character monster with
> template parameters; I usually give in and a write a for() loop for that
> reason (i.e. it is quicker to type the for() loop out than go hunting
> through my code to get the exact class name definition).

This is off-topic, but invoke the help of your text editor here. If I
have a class named SomethingReallyHorribleAndLong, I don't retype its
name all over the place, rather I type "Som^P" and vim (my editor)
expands it into "SomethingReallyHorribleAndLong". (This doesn't help
make the code less ugly to look at, but it does make it easier to
type.)

> >Note that if "save" were defined by MyClass as a functoid, things get
> >even easier in the client code; see the attached example (and YourClass)
> >for details.
>
> Have you thought of supplying some macros to help - my eyes kept bouncing
> off the code in YourClass.

No--you almost never do this (what I did in YourClass) anyway. Rather you
usually would just choose to make "save" a "global" functoid (this goes
along with some general C++ wisdom anyway; see
   http://www.cuj.com/documents/s=8042/cuj0002meyers/
for example), and thus call
   save( yc, f ); // or yc ^save^ f
rather than
   yc.save(f);
That is the simple solution; the stuff I showed with YourClass just
illustrates how it's possible to get "cute" and use functoids with
member syntax.

Again, it's a matter of what you are going to do with your
classes/methods. If you want to use them lots in FC++, making lots of
higher-order functions and lambda expressions, then you should write
functoids. If not, then just write classes/methods as usual, and be
willing to occasionally have to spell out ptr_to_fun(&MyClass::save).

> >... the gist of it would again be that
> >
> > bind(&MyClass::on_name, this, _1,_2)
> >
> >would be spelled
> >
> > ptr_to_fun(&MyClass::on_name)(this)
>
> Interesting. I cannot decide if I like _1,_2 disappearing or not (I'm
> trying to think about
> when I look at it in 6 months time).

If you do lots of functional programming, then you'll grow so
accustommed to currying (leaving off trailing arguments) that you won't
even think about it. I suppose an FP-er is more likely to write
   foldl(op)
whereas others might prefer
   foldl(op,_,_)
since foldl takes 3 arguments.

-- 
-Brian McNamara (lorgon_at_[hidden])

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