Boost logo

Boost :

Subject: Re: [boost] Formal Review: Boost.RangeEx
From: Giovanni Piero Deretta (gpderetta_at_[hidden])
Date: 2009-02-25 17:01:14


On Wed, Feb 25, 2009 at 10:11 PM, Thorsten Ottosen
<thorsten.ottosen_at_[hidden]> wrote:
> Vicente Botet skrev:
>
>>> Dear Giovanni,
>>>
>>> On Wed, Feb 25, 2009 at 5:13 PM, Giovanni Piero Deretta
>>> <gpderetta_at_[hidden]
>>>>
>>>> wrote:
>
>>> Yes, I think I might have over-emphasised the difference. Would you
>>> prefer
>>> the function overload to be in the boost::adaptors namespace, the boost
>>> namespace or something else?
>>>>>
>>>>> I had considered
>>>>> creating a range adaptor to be highly different to applying an
>>>>> algorithm,
>>>>> perhaps I over-emphasised this distinction when making the decision.
>>>>
>>>> FWIW, I have code like this:
>>>>
>>>> total = ( r | filter(_r, f) | map(_r, m) | accumulate(_r, zero, a)  );
>>>>
>>>> i.e. I don't have a strong distinction between adaptor and algorithms.
>>>>
>>> Yes, I'm sold!
>>
>>  I agree, the introduction of the parameter (_r) makes the library
>> homogeneus. An adaptor is a functor with a placeholder for the input
>> parameter.
>
> I my examples I removed the _r from the syntax. I don't see the point in
> having them, if the code can work without them. Are they really needed?
>

No, not necessarily:

    1: transformed_range<...> r = transformed(range, f);
    2: transformed_range<...> r = range | transformed(f);

you could have the single argument variant of transformed (and in
general the variant with arity N-1 of an adaptor) return 'something'
that can function in a pipe. I would expect that 'something' to be a
full fledged unary function object (the equivalent of
bind(transformed, _1, f)) that can also work outside of pipes or even
stored:

    boost::function<transformed_range<range_t, f_t>(range_t)> mapper =
transformed(f);
    // or alternatively
    boost::result_of<mapper_t(f_t)>::type mapper = transformed(f);
    BOOST_FOREACH( v_t v, range | mapper) { ... }

Which implies that transformed (and other adaptors) should store 'f'
(and other parameters) by value (modulo boost::ref and friends).

( BTW If you decide to adopt this solution, I suggest putting the
range parameter last. This way It would sort of simulate the automatic
currying syntax of some functional languages (where omitting the last
m parameters of n-arity function makes it a higher order function that
returns an (n-m) arity function. )

This approach has unfortunately a big problem. If you have adaptors
with optional arguments, without concepts it is an iteresting problem
figuring out which overload the user wants:

   merged(r1, r2); // uses operator< as comparator
   merged(r1, r2, cmp); // uses cmp as comparator
   r1 | merged(r2, cmp); // interesting problem here!
   r1 | merged(_r, r2, cmp); // much better
   r2 | merged(r1, _r, cmp); // we have a choice of the argument to bind
   r1 ^merged(_r1, _r2, cmp)^ r2; // probably beyond the scope of the library ;)

In my code, I use '_' as a placeholder, instead of '_r'.

-- 
gpd

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