Subject: Re: [boost] Assign V2 - first impression
From: er (er.ci.2020_at_[hidden])
Date: 2011-06-24 11:09:31


On 6/24/11 9:08 AM, Stewart, Robert wrote:
> er wrote:
>>
>>> I am sure that it is a powerful library, but I really have no
>>> idea at all what is going on. I can't even parse the first
>>> line as valid C++ in any way. You need better examples, and
>>> also is that really the best way you could find to express
>>> repeating?
>>
>> If I try to imagine what the interface would look like after
>> taking into account some of the suggestions that were made, this
>> sentence:
>>
>> "Create data elements by mapping 1, 10, 100, 1000 by function
>> f, and insert each result in cont by invoking modifier
>> push_front."
>
> If I interpret that correctly, it would be clearer as:
>
> "Create elements in cont, using push_front(), by calling f() 1, 10, 100, and 1000 times."
>

Noted, thanks.

>> translates to
>>
>> (
>> push_front<1>( cont ) % ( _data = f ) % ( _repeat = n )
>> )( 1, 10, 100, 1000 );
>
> Why the leading underscores on "_data" and "_repeat?"

It's part of a set of conventions that are pervasive throughout the
library: trailing underscore for types, leading one for const objects:

const name_ _name = {};

Names without underscores are reserved for functions.

>
>> Questions :
>> - is it more readable, now?
>> - What if each example was preceded by its English equivalent.
>
> Preceding each by a clear English equivalent is necessary.

Noted.

>
> Could that code be spelled like the following instead?
>
> push_front<1>(cont).from(f).repeated(1, 10, 100, 1000);
>
> That is, instead of operator overloading, member functions would make things clearer and more succinct. Is there more to the operator

overloading than I know making the member function approach too
restrictive? What happens to your operator overloading approach when a

To use a proverbial expression, the member function approach is "carved
in stone", if you like. Not using operator%. I'm going to assume that
'object' is returned by put( cont ) or deque<T>( _nil ). It doesn't
matter which, since they rely on the same implementation. Consider

( object % option1 % ... % optionn )(1, 10, 100, 1000);

object has two (orthogonal) components : the data-generator, which maps
arguments to a data-element, and the modifier which takes care of
inserting that data-element. Each option modifies either of these two
components. For example

( object % ( _data = f ) )( 1, 10, 100, 1000 );

changes the data-generator to f. For example,

( object % ( _repeat = n ) )( 1, 10, 100, 1000 );

wraps a new modifier around the one that already resides in object (say
push_back), such as to invoke it n times.

While this is perhaps not as intuitive as desired, it's in my view an
irreducible price to pay to have modularity and open for extension : one
can customize an option.

I anticipated that this would be a problem and already provided some
remedy (I won't delve on it), but did not push the reasoning far enough.
The next step, I think, is to try to get back to functions, as you
suggest, but free functions, not member functions. I already proposed a
new syntax. Let me repeat it:

push_front<1>( cont )( 1, 10, 100, 1000 );

would be equivalent to the less eye candy

( put<1>( cont ) % _push_front )( 1, 10, 100, 1000 );

Consequently, using the first form, the use of operator% would appear,
only for additional options:

( push_front<1>( cont ) % ( _data = f ) % ( _repeat = n ) )( 1, 10,
100, 1000 );

One way to see that being able to encapsulate an option as an object is
a good thing, however, is to imagine to have to write two unit tests:

void unit_test1()
{
     std::deque<T> v;
     v.push_back( T( args1... ) ); ...; v.push_back( T( argsn...) )
     // whatever
}

void unit_test2()
{
     std::deque<int> v;
     v.push_front( T( args1... ) ); ...; v.push_front( T( argsn...) )
     // whatever
}

With V2, you can do the same like this:

template<typename Option>
void unit_test(Option option)
{
     std::deque<int> vec;
     ( put( vec ) % option )( args1... )...( argsn... );
     // whatever
}

unit_test( _push_back );
unit_test( _push_front );

Some people might find this contrived. Fair enough, but it's meant to
make a point about modularity, which should have some benefit in less
contrived situations.

HTH, and thanks for your interest.