Boost logo

Boost :

Subject: Re: [boost] Formal Review: Boost.RangeEx
From: David Abrahams (dave_at_[hidden])
Date: 2009-03-02 10:01:00


on Fri Feb 27 2009, Rogier van Dalen <rogiervd-AT-gmail.com> wrote:

> To me, RangeEx provides functions that take a range and return a range.
> How is it not most natural to make these functions look like
> functions?

Every bit of runtime functionality is most naturally-expressed as a
function call, according to some people. Those people end up writing
code with lots and lots of parentheses, and they cite this uniformity as
a source of expressiveness. Personally, I don't get it. If there's a
more evocative syntax, we should consider using it.

Function call syntax (in general) expresses a tree structure.

         f( g( a( b, c ), d( e, z, h) ), i(j, k) )

                        f
                  ______|______
                 / \
                g i
             ___|___ / \
            / \ j k
           a d
          / \ /|\
         b c e z h

What we're doing with RangeEx (in general) only expresses a degenerate
tree structure (i.e. a linear structure):

       r | transform(f) | filter(g) | whatever(h)

       = whatever(filter(transform(r, f), g, h))

There's a _lot_ wrong with that way of expressing it, not least that
oerations (such as filter) are separated from their essential parameters
(g). Personally I think the top-down order in which the function call
syntax reads is also much harder to understand.

> What is wrong with saying "uniqued(rng)"? Why is it vital that the name
> has "make_ _range" to remind me that this returns a lazy range rather
> than a range?

I don't think "make_ _range" does anything to indicate laziness.

Here's how I think of it:

  unique_range => a type. No need to say "lazy_unique_range" because if
                  it weren't lazy, we wouldn't need a type.

  unique(r) => a function returning unique_range

> could you state how you would
> integrate lazy merge() or anything that takes two or more ranges in
> operator| syntax?

There are lots of options, but

      merge(r1, r2)

is not a bad one. The alternatives generally look like

      r1 # r2

where # is some operator (or pseudo-operator such as %merge%). In the
end you will usually want to add parentheses as in

    (r1 | r2) # (r3 | r4)

and then if you want to continue chaining,

    ((r1 | r2) # (r3 | r4)) | r5

which I don't think is an improvement over

    merge(r1 | r2, r3 | r4) | r5

> I believe that the '|' syntax, however cute (I agree there!) is less
> flexible and less obvious than the function syntax.

Agreed w.r.t. flexibility; disagreed w.r.t. obviousness. As is often
the case, a more limited and specific form of expression makes for
clearer syntax (e.g. BNF illustrates syntax better than a hand-coded
parser in a general-purpose programming languages)

> Currently merge(), transform(), and the set algorithms use output
> iterators as a substitute for return values. Rephrasing them as
> functions would also get rid of output iterators, which would improve
> their interface.

While value semantics are wonderful, I have doubts that everything that
operates on output iterators can be effectively reformulated to return a
range without limiting expressiveness and efficiency.

-- 
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

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