Boost logo

Boost :

From: Vladimir Prus (ghost_at_[hidden])
Date: 2004-04-09 09:21:13


I've just made a first attempt to read through FC++ docs, and have some
comments. I haven't read all of the posts in the recent review, so apologies
if some of the issues are already known. The docs I used are those at
http://www.cc.gatech.edu/~yannis/fc++/boostpaper/fcpp.html

First, a motivating example: I wanted to find a vertex in BGL graph which has
in degree of zero. This should be something as simple as (using lambda):

    find(vertices(g).first, vertices(g).end(),
           bind(in_degree, _1, g) == 0);

but in_degree happens to have several overloads, all of which are templates,
so just 'in_degree' won't work, and selecting the right variant via cast has
it's own problems.

So, I though FC++ would allow me to declare 'in_degree_f' object that will
work for all kinds of graph.

The documentation starts with:

    FC++ is a library for doing functional programming in C++. The library
    provides a general framework to support various functional programming
    aspects, such as higher-order[1] polymorphic[2] functions,

The issues with this are:
1. When this is in context of proposed Boost.FC++ docs, one immediately
wonders how this is different from Boost.Lambda.
2. The footnotes always break the regular flow of reading, so it's better not
use them in the first sentence new user is likely to see.
3. higher-order polymorphic functions exists even without FC++. I think
boost::bind is such a function: it takes function as argument and returns a
function. So, this statement does not indicate what new FC++ brings (btw, I
agree it brings something new).
4. If you think that average reader will think that 'polymorphic' == 'with
virtual functions' you might want to use the word 'generic'.

Later, you define 'functiod' and the definition applies just nice to
functional objects everybody was using for quite some time. Again, you don't
explain what FC++ brings.

Later, you describe changes made during boostification. I really don't think
new user would be interested in that.

The above comments might sound like nit-picking, but what I try to say is:
the instroduction does not say absolutely anything about why FC++ is worth
looking at. The only new term there is 'lazy_list' and if reader doesn't know
what's that already, he might not get even that.

In section 2, you say:

   Programming in this pure style ensures referential transparency.

and I don't know what "transparency" here means.

Now, to section 4, "Overview". What I'd expect in this section is a bunch of
examples, showing what I can do with FC++ which is not easily done using
other tools. What I see, though, is:

    We could define a polymorphic functoid add_self(), which adds an argument
    to itself:
     // add_self( x ) means x + x

If we can define such thing, I'd really like to see the definition, not
commented out code. The you talk about lazy list, again for someone who has
no idea what they are, it's hard to understand usefullness. I think you
should either explain this with an example, or at worst give some link. E.g.
"Why functional programming matters" makes some use of lazy lists, IIRC.

The overview does on in largely the same style. You list supported functoids
but don't give any explanations or example. Last comment on this section:

    plus(3,4) // 3+4 also minus, multiplies, etc.

This does not look impressive. Can't I do "std::plus<int>(3,4)". I think one
of the points of FC++ is that you don't need to specify the exact type. If
so, you need to explicitly state that fact (and preferrable, even in the
introduction).

Now to the Section 5.

   Direct functoids enable the creation of functions

Hmm.. is it precisely "enable". I suspect that "direct functoid" *is* the
function. Or is direct functoid is some device which produces functions?
I think the example with 'map' is not really good. First you say map takes a
list and function. Then you give Haskell syntax and describe that syntax.
After that you explain what's high-order and what's polymorhic. IMO, the
Haskell syntax is just not necessary here.

Later you say:

   Representing such a function in C++ is non-trivial

Then, what about std::transform? If we forget that it works on iterators, not
sequences (which is just detail) then it does exactly what you're after.

I think it would be better if you write down properties of the function you
want to create (polymorphic, can be passed as argument *itself*, allows to
inter return type) and then immediately give an example. And example could be
more reabably you use split the definition of 'result_type' like this:

template <class F, class L>
      struct sig {
         typedef F::template sig<typename L::value_type>::result_type function_return
         typedef list< function_return > result_type;
      };

It might be better to use 'type' instead of 'result_type' since MPL uses
'type'.

When you talk about monomorphic direct functoids, I wonder why you need
'c_fun_type'. Is it possible to make std::unary_function work?

The section 6, "Indirect Functoids", makes me wonder if they are usefull at
all. boost::function works very nice with me, and it also works with
boost:bind.

The secton 7, "Full Functoids" looks ok to me, though some examples would be
good.

At this point I've stopped reading documentatation, tried to write some code
and got my 'in_degree_f' in a short time. There are some additional
questions:

1. Maybe it makes sense to provide a helper base class for a case where return
type is fixed, but argument types are not. Something like:

    class xxx_in_degree : public ret_type2<unsigned> { ... } ;

2. Do we need intermediate typedef? Won't

   boost::fcpp::full2<xxx_in_degree> in_degree_f;

work just fine?

3. I have

    std::find_if(vertices(g).first, vertices(g).second,
                     in_degree_f(_, g));

but I want to compare the return from 'in_degree_f' with zero, as in thes
example:

    find(vertices(g).first, vertices(g).end(),
           bind(in_degree, _1, g) == 0);

How do I do that? When I try:

     std::find_if(vertices(g).first, vertices(g).second,
                     lambda(X)[ in_degree_f[X, g] %equal% 0]);

I get a lots of errors, starting with:

   fcpp/signature.hpp:114: error: invalid use of undefined type `struct
       boost::fcpp::impl::XEqual::sig<size_t, int>'

The complete example is at http://zigzag.cs.msu.su:7813/bgl.cpp if needed.

Also, it would be *really* nice if lambda syntax in FC++ and Boost.Lambda was
compatible. I'll print and read your paper on syntax today, but no matter how
big semantic differences are, learning/using two different syntaxes is a bad
idea.

These are all comments for now. Hope they make sense.

- Volodya


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