Boost logo

Boost :

From: Jared Roberts (jared+boost_at_[hidden])
Date: 2004-03-02 01:10:15


I don't know what the boost rules are as far as random strangers giving
drive-by reviews (do you have to be a member or anything-- feel free to
ignore me if I'm out of place), but I thought I'd chime in in case I
accidently say something useful.

This probably isn't in-depth enough to be a real review, but from what
I've seen of FC++, if I had a vote, I would vote to accept FC++ into
boost, conditional on the author fixing some things up (non-const refs,
dropping the N from fullN, and many of the suggestions by Jonathan
Turkanis).

* What is your evaluation of the design?

To help me evaluate the design, I wrote a few quick client programs to
try and get a feel for the 'language'. The most instructive of these,
was a quicksort function, modelled after the example given on the
haskell home page ( http://www.haskell.org/aboutHaskell.html ):

template<typename ordT>
struct quicksort : public c_fun_type<list<ordT>, list<ordT> >
{
     list<ordT> operator()(list<ordT> in) const
     {
         if(null(in)) return NIL;

         lambda_var<1> X;
         lambda_var<2> pivot;
         lambda_var<3> tl;
         lambda_var<4> lefts;
         lambda_var<5> rights;
         lambda_var<6> qs_rec;
         return lambda()[
              let [
                   pivot == head[in],
                   tl == tail[in],
                   lefts == comp_m<list_m>()[X | X <= tl,
                                                 guard[X %less% pivot]],
                   rights == comp_m<list_m>()[X | X <= tl,
                                                 guard[X %greater_equal%
                                                                 pivot]],
  /* (A) */ qs_rec == full1<quicksort<ordT> >()
              ].in[
  /* (B) */ qs_rec[lefts] %cat% (pivot %cons% qs_rec[rights])
              ]
         ]();
     }
};

I've been generally impressed with the design. There are a few things
that bother me. I dislike having to manually promote direct functoids
to full functoids. This is particularly sticky if the functoid is
recursive, as above. I worked around this at (A) by using a lambda
variable to hold the full functoid, but I would have thought there was a
better way. If there is, I didn't see it in the documentation. I also
could have had a member typedef quicksort::full or something, but I find
that even worse.

On a positive note, I really like the explicit lambda syntax. Most of
what I've seen from others has stated that it's not as easy to use as
boost::lambda, or that it's too verbose. I disagree-- I found it very
frustrating to read the boost::lambda documentation and try and remember
all these little rules about when to use protect() or unlambda() or
constant() or make_const() or whatever. Further, the explicit lambda
syntax is much more convienant when constructing nested lambdas, since
you can still access variables in the outer scope. It's unfortunate
that the variables require a unique integer template parameter, but I
don't think this really limits their usefulness.

One thing in particular that seems to have been overlooked by some
others about the lambda variables is that they allow you to do a fair
amount of type inference! Looking again at the quicksort example,
rather than worry about types, I just declared everything lambda and the
compiler was able to figure everything out. This is true even for
qs_rec, which is bound to the full-functoid version of quicksort to be
used in the recursive step at (B). FC++ is able to figure all this out,
even though qs_rec isn't bound when declared. It's not quite "auto",
but it's pretty cool!

(side note: Is there any reason the lambda() has to be there at all?
It seems a bit silly to define a lambda and then immediately evaluate
it. Shouldn't the let ideally be able to suffice here?)

* What is your evaluation of the implementation?

I didn't look at the code enough to have an intellegent opinion on this.
  Everything I did seemed to work as advertized though, so at least it's
relatively bug-free.

* What is your evaluation of the documentation?

The documentation isn't great. I don't think it's as terrible as some
have made out, but there were numerous times I had questions and was
unable to find an answer. One of the questions I had did have a
solution in the documentation (use make_manip()-- ick), but I didn't
find it in the docs before I worked it out on my own. In some cases,
I'm still not sure, for example: In the quicksort example again, at
(B), there is a recursive call "qs_rec[rights]". Is this call
automatically lazy? Or do I have to do something to it? Earlier
versions of the code didn't have this part wrapped up in a lambda, and I
was able to do thunk1(qs_rec, rights), but I couldn't figure out what I
needed to do here. My hunch is that I need to do nothing, but I
couldn't find anything that told me so for sure.

* What is your evaluation of the potential usefulness of the library?

I think FC++ would be most useful in the business logic portions of
applications that contain a heavy amount of interface code to the
outside world. My understanding is that FP most shines for the sort of
pure-data calculations that you'd normally do in a spreadsheet,
Mathematica or S-plus. Using FC++ would make it easer to write bug-free
  logic (once the dang thing compiles, it's amazing how it seems to just
DTRT), while still tying in to a C++ UI, a database, network services
and whatever else is easier to do in an imperative way, or for which
bindings do not exist for functional languages. Having FC++ as part of
boost would help guarantee that the transition from "normal" C++ code to
functional C++ code is a smooth one-- or at least that the pitfalls are
known.

For myself, I look forward most to being able to use lambda library. I
know this is probably the part that most overlaps with existing parts of
boost, but I think the two libraries have slightly different goals. The
boost::lambda library seems most useful when you need a terse little
functor to drop into an STL algorithm, whereas the FC++ lambda library
seems to be useful who basically see their whole function as one big,
nested lambda (which is the FP viewpoint). As I mentioned, I also
believe that FC++ strives more for KISS, while BLL aims more for
handling the common cases automatically (for example, the overloading of
"<<")

* Did you try to use the library? With what compiler? Did you have any
problems?

I used g++ 3.3. The only problem was slow compliation times. And
trying to wrap my head around what was going on :)

* How much effort did you put into your evaluation? A glance? A quick
reading? In-depth study?

I've been anxiously awaiting FC++'s introduction to boost since I first
found out about FC++ in Brian's review request last summer/fall. I read
  the papers on his website at that tme and have since revisted them. I
also read through the new boost docs and monkeyed around for awhile. If
you pushed it all together, it'd probably be a solid couple of days.

* Are you knowledgeable about the problem domain?

Not really. I had a class in functional programming using SML. I
discovered Haskell while listening to a presentation about Functional
Images ( now at http://conal.net/papers/functional-images/ ). I then
tried to read the Gentle Introduction to Haskell, and got about as far
as Monads, when my head promptly exploded. I see FC++ as a good way to
approach this again, while staying in familiar territory.

* Do you think the library should be accepted as a Boost library?

I do. There are a fair number of improvements suggested by others that
I don't disagree with, and although some seem larger in scope, when
taken in consideration with the overall size of the library itself, I
don't think any of the problems is so large as to require a later review
before acceptance.


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