From: Paul Bibbings on
DeMarcus wrote:
> Hi,
>
> I have an object:
>
> class SomeObject
> {
> public:
> SomeObject();
>
> SomeObject& setValue( int i );
> SomeObject& increaseRate( int percent );
> ... etc ...
> };
>
> This is used in the following manner
>
> startCalculation( SomeObject().setValue( 47 ).increaseRate( 20 ) );
>
>
> Now, I want to provide a small wrapper ensuring correct initialization.
> My question is; shall I use derivation or a function? I.e.
>
> struct PreparedObject : SomeObject
> {
> inline PreparedObject( int i, int percent ) : SomeObject()
> {
> (*this).setValue( i ).increaseRate( percent );
> }
> }
>
> or shall I use a function:
>
> inline SomeObject preparedObject( int i, int percent )
> {
> return SomeObject().setValue( i ).increaseRate( percent );
> }
>
>
> Later those would be used like this
>
> startCalculation( PreparedObject( 47, 20 ) );
>
>
> Both derivation and using a function work, but what are the pros and
> cons? What is most elegant, efficient, safe, etc.?

Having followed through what you seem to be trying to do here, and supposing
that the calls to SomeObject::setValue(int) and SomeObject::increaseRate(int)
are not simple initializations (i.e., may involve calculations), then I can't
see what any of your ideas gain over the simple:

class SomeObject
{
public:
SomeObject(int i, int percent)
{
setValue(i);
increaseRate(percent);
}
SomeObject& setValue(int i)
{
// do stuff with i
return *this;
}
SomeObject& increaseRate(int percent)
{
// do stuff with percent
return *this;
}
private:
// ...
};

void startCalculation(SomeObject) { }

int main()
{
startCalculation(SomeObject(47, 20));
}

If they /are/ just initializations, then use a two-arg constructor and a
mem-initializer list.

Though not intended to be merely a dig, I have picked up from other similar
ideas that you have presented that you have a leaning towards wanting to use
chaining at the call site to functions that starts to feel a little `unhealthy'
(i.e., counter-productive), especially when you are having to add layers of
inheritance, or whatever, just to make it `work'. With respect, you might want
to ask yourself if you are doing it differently (i.e., against convention)
merely to /be/ different.

I can't see how this:

startCalculation( SomeObject().setValue( 47 ).increaseRate( 20 ) );

or, especially this:

startCalculation( PreparedObject( 47, 20 ) );

can ever achieve anything - *especially* where you are passing a temporary that
doesn't exist outside of the call - over:

startCalculation(SomeObject(47, 20));

Chaining is `pretty'. It doesn't always *solve* very much.

Regards

Paul Bibbings

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: DeMarcus on
Goran wrote:
> On Jun 15, 11:15 am, DeMarcus <use_my_alias_h...(a)hotmail.com> wrote:
>> Hi,
>>
>> I have an object:
>>
>> class SomeObject
>> {
>> public:
>> SomeObject();
>>
>> SomeObject& setValue( int i );
>> SomeObject& increaseRate( int percent );
>> ... etc ...
>>
>> };
>>
>> This is used in the following manner
>>
>> startCalculation( SomeObject().setValue( 47 ).increaseRate( 20 ) );
>
> I've seen code like this (even wrote some in my time), and I've come
> to despise it. The major problem I see with this is that your
> modifiers are misleading in form. What they buy is the ability to call
> multiple methods on an object in one statement. Uh-oh, big deal.
>

I'm in a design phase right now and need all input I can get. Can you
please explain a bit further; what part is it that you don't like? Is it
the function chaining, the temporary object, both, or something else?

>> Now, I want to provide a small wrapper ensuring correct initialization.
>
> Erm... That's what constructor is for?
>
> On a more general note, it looks like you are using two-step
> initialization. In my opinion, there has to be a big fat explanation
> for every use. So what's your excuse? ;-)
>

As Daniel Kr�gler guessed, I'm not allowed to change the constructor of
SomeObject, and even if I could, the number of permutations would be
gastronomical.

One could see SomeObject as a general settings object where the normal
use would be

startCalculation( SomeObject().setValue( 47 ).increaseRate( 20 ) );

while better compile-time safety could be achieved, forcing some of the
optional parameters be mandatory, with wrapper helpers like so

startCalculation( PreparedObject( 47, 20 ) );

or even

startCalculation( IncreasedRate20( 47 ) );


>> My question is; shall I use derivation or a function? I.e.
>>
>> struct PreparedObject : SomeObject
>> {
>> inline PreparedObject( int i, int percent ) : SomeObject()
>> {
>> (*this).setValue( i ).increaseRate( percent );
>> }
>>
>> }
>>
>> or shall I use a function:
>>
>> inline SomeObject preparedObject( int i, int percent )
>> {
>> return SomeObject().setValue( i ).increaseRate( percent );
>>
>> }
>>
>> Later those would be used like this
>>
>> startCalculation( PreparedObject( 47, 20 ) );
>
> If this is __really__ the only way you are happy with :-), I'd say
> that a function is better, simply because it's less code artifacts.
> (Derivation meant a class and a trivial ctor. That's incidental
> complexity, not much more)
>

A function may seem the obvious choice for most here, but to be picky,
will I not get a slight performance hit compared to derivation since I
have to return the object? Or will the function inlining take care of that?



--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: DeMarcus on
Paul Bibbings wrote:
> DeMarcus wrote:
>> Hi,
>>
>> I have an object:
>>
>> class SomeObject
>> {
>> public:
>> SomeObject();
>>
>> SomeObject& setValue( int i );
>> SomeObject& increaseRate( int percent );
>> ... etc ...
>> };
>>
>> This is used in the following manner
>>
>> startCalculation( SomeObject().setValue( 47 ).increaseRate( 20 ) );
>>
>>
>> Now, I want to provide a small wrapper ensuring correct initialization.
>> My question is; shall I use derivation or a function? I.e.
>>
>> struct PreparedObject : SomeObject
>> {
>> inline PreparedObject( int i, int percent ) : SomeObject()
>> {
>> (*this).setValue( i ).increaseRate( percent );
>> }
>> }
>>
>> or shall I use a function:
>>
>> inline SomeObject preparedObject( int i, int percent )
>> {
>> return SomeObject().setValue( i ).increaseRate( percent );
>> }
>>
>>
>> Later those would be used like this
>>
>> startCalculation( PreparedObject( 47, 20 ) );
>>
>>
>> Both derivation and using a function work, but what are the pros and
>> cons? What is most elegant, efficient, safe, etc.?
>
> Having followed through what you seem to be trying to do here, and supposing
> that the calls to SomeObject::setValue(int) and SomeObject::increaseRate(int)
> are not simple initializations (i.e., may involve calculations), then I can't
> see what any of your ideas gain over the simple:
>
> class SomeObject
> {
> public:
> SomeObject(int i, int percent)
> {
> setValue(i);
> increaseRate(percent);
> }
> SomeObject& setValue(int i)
> {
> // do stuff with i
> return *this;
> }
> SomeObject& increaseRate(int percent)
> {
> // do stuff with percent
> return *this;
> }
> private:
> // ...
> };
>
> void startCalculation(SomeObject) { }
>
> int main()
> {
> startCalculation(SomeObject(47, 20));
> }
>
> If they /are/ just initializations, then use a two-arg constructor and a
> mem-initializer list.
>
> Though not intended to be merely a dig, I have picked up from other similar
> ideas that you have presented that you have a leaning towards wanting to use
> chaining at the call site to functions that starts to feel a little `unhealthy'
> (i.e., counter-productive), especially when you are having to add layers of
> inheritance, or whatever, just to make it `work'.

No, it's not just to make it work. It's a safety extension. See below.

> With respect, you might want
> to ask yourself if you are doing it differently (i.e., against convention)
> merely to /be/ different.
>
> I can't see how this:
>
> startCalculation( SomeObject().setValue( 47 ).increaseRate( 20 ) );
>
> or, especially this:
>
> startCalculation( PreparedObject( 47, 20 ) );
>
> can ever achieve anything - *especially* where you are passing a temporary that
> doesn't exist outside of the call - over:
>
> startCalculation(SomeObject(47, 20));
>
> Chaining is `pretty'. It doesn't always *solve* very much.
>

Please correct me if I'm wrong, but chaining is the only really good
solution to provide optional parameters when the number of parameters
grow large.

Since the number of permutations of the optional parameters is so great
I cannot have them in the constructor of SomeObject. My first thought
was to create something like

SomeObjectA
SomeObjectB
....
SomeObjectQ

for each permutation, but I skipped that since I didn't want to force
the programmer to create an object for each permutation, hence the
general SomeObject with chaining.

Now, I still want to provide the /ability/ of creating SomeObjectA, etc.
(or functions) for the reason that it forces a compile-time check of the
provided parameters. Now the programmer can pinpoint certain often-used
permutations and make sure they will always get right. E.g.

startCalculation( DefaultSettings() );


All ideas about optional parameters are welcome. Thanks for your input!

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Jeff Flinn on
DeMarcus wrote:
> Paul Bibbings wrote:
>> DeMarcus wrote:
>>> Hi,
....
> All ideas about optional parameters are welcome. Thanks for your input!

Have you looked at
http://www.boost.org/doc/libs/1_43_0/libs/parameter/doc/html/index.html

Abstract:

Use this library to write functions and class templates that can accept
arguments by name:

new_window("alert", _width=10, _titlebar=false);

Since named arguments can be passed in any order, they are especially
useful when a function or template has more than one parameter with a
useful default value. The library also supports deduced parameters; that
is to say, parameters whose identity can be deduced from their types.

Jeff

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Alf P. Steinbach on
* DeMarcus, on 16.06.2010 15:57:
>
> Please correct me if I'm wrong, but chaining is the only really good
> solution to provide optional parameters when the number of parameters
> grow large.

Jeff Flinn has alredy mentioned the Boost Parameters Library, which does not
depend on chaining.

But it is a bit impractical for constructor arguments in the context of inheritance.


> Since the number of permutations of the optional parameters is so great
> I cannot have them in the constructor of SomeObject. My first thought
> was to create something like
>
> SomeObjectA
> SomeObjectB
> ...
> SomeObjectQ
>
> for each permutation, but I skipped that since I didn't want to force
> the programmer to create an object for each permutation, hence the
> general SomeObject with chaining.
>
> Now, I still want to provide the /ability/ of creating SomeObjectA, etc.
> (or functions) for the reason that it forces a compile-time check of the
> provided parameters. Now the programmer can pinpoint certain often-used
> permutations and make sure they will always get right. E.g.
>
> startCalculation( DefaultSettings() );
>
>
> All ideas about optional parameters are welcome. Thanks for your input!

Usage examples for a general chaining-based solution that supports inheritance
(i.e., it generates covariant setters) is available here:

http://alfps.wordpress.com/2010/05/19/cppx-how-to-do-typed-optional-arguments-in-c98/

It links further to the FAQ, to a DDJ article, to an earlier article posted in
this group, to earlier discussion in [comp.lang.c++], and to full code for the
discussed general solution in a ZIP archive at Google Docs.

The DDJ article additionally gives a usage example for the Boost Parameters
Library (possibly not the cleanest possible but the best that I could think of),
and discusses why BPAL may be undesirable and chaining preferable.


Cheers & hth.,

- Alf

--
blog at <url: http://alfps.wordpress.com>

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]