Boost logo

Boost :

From: William Kempf (sirwillard_at_[hidden])
Date: 2000-11-22 15:08:52


--- In boost_at_[hidden], Karl Nelson <kenelson_at_e...> wrote:
> > --- In boost_at_[hidden], Kevlin Henney <kevlin_at_c...> wrote:
> > As for why it's desirable... it eliminates redundant information
from
> > the declaration. Why should you have to specify the number of
> > parameters when you declare the type with explicit parameters?
It's
> > just cleaner to say:
> >
> > callback<void, int, float> cb;
> >
> > instead of:
> >
> > callback2<void, int, float> cb;
>
> I really don't agree with this.

It's good to hear counter arguments.
 
> 1) All of the classes written to
> hide the extra arguments inevitably show up when an error occures
> thus spitting something like this to the user...
>
> an error has occured in class
callback<void,int,float,unused,unused,unused>
>
> Thus it really isn't transparent to the user.
>
> (See the horrible errors spit by basic_string as to how annoying
this
> can be.)

I don't find the errors to be "horrible" or unreadable. Nor do I
think it's bad that the "unused" types appear in the error text. The
point isn't to completely hide the details, it's to make useage
simpler and more intuitive.
 
> 2) Second it makes for really poor code clarity as the class will
> have to implement all of the operator() even through it uses
> only one of them...
>
> class callback {
> ...
> return_type operator()() { ... }
> return_type operator()(P1 p1) { ... }
> return_type operator()(P1 p1,P2 p2) { ... }
> return_type operator()(P1 p1,P2 p2,P3 p3) { ... }
> return_type operator()(P1 p1,P2 p2,P3 p3,P3 p3) { ... }
> ...
> };

I'm not sure that "code clarity" is impacted by much, and with proper
documentation and code comments I think this a non-issue.
 
> 3) It only saves one charactor. :-)

The point isn't the amount of typing, but rather of intuitive useage
(which is admittedly debatable). Repeating information generally
just makes comprehension more difficult. This is made worse by the
fact that callback1 takes 2 template parameters. For someone
unfamiliar with the class this could lead to confusion.

> The same things could be achieved
> with a base class with all the common stuff and then derive it to
> add the arguments.
>
> class callback { // not a template
> bool empty();
> void clear();
> ... // common stuff
> };
>
> template <class R, class P1 >
> class callback1 {
> ... // specific stuff
> R operator()(P1 p1);
> };

I assume you forgot the derivation in the above?

This does not illustrate "the same things being achieved".

> Which insidentally extracts with VC++ and other code browsers
> to make more sense.

I don't follow what you're saying here.
 
> 4) It bars adding additional optional arguments which may be
> useful. Ie, since the callback may be unconnected how do we
specify
> what to return in case of there is nothing connected.
>
> imagine this
>
> template <class R, class P1, class P2, class RT=trait<R> >
> class callback2
> {
> R operator()(P1 p1,P2 p2)
> { if (empty) return R(RT::default_value); ... }
> };
>
> (This also saves the default constructor argument.
> SigC uses this for a number of classes. (Though I
> avoid it for slots as then copy gets fun.)
>
> Without the number you have to write something like...
>
> callback<void,int,unused,unused,unused,my_return_trait>
> ^^^^^^^
> (how many should I type? depends on the version of the library!)

Well, we weren't discussing having any optional template parameters.
There's alternatives to this idiom that could be applied if it were
deemed appropriate to have such optional parameters. Of the
arguments you've given, this is the most persuasive, but I'm not sure
it's enough to sway my opinion.
 
> 5) It caps the number of callback which limits the application
> somewaht. That is with the callback#, the user can always call
> the macro generator to produce another set of classes for a
> larger number of parameters.

The "macro generator" can just generate a new class with more
optional parameters. I don't think this is an issue either.
 
> 6) It encourages gobs of template land meta programming which can
slow
> some compilers to a grinding halt and is some of the least portable
code
> back to the weaker compilers. ( Read we will get something which
> VC++ likes but is kludgy as all hell.) Then again implementing
> many levels of class can do the same.

This may be a problem today (in this case, I don't think it is, since
the code in question works fine with VC++, the weakest of compilers,
and is not very "kludgy" IMHO), but tomorrow it could be a non-
issue. For that reason, I'm not sure this is a valid argument either.
 
> For all of these reasons SigC went with numbered classes.
> I hope you consider carefully these reasons before chosing to do
> differently.

I should note that this practice is not something new. The Lambda
tuples use this idiom for much the same reasons that I would prefer
it to be used here. The one argument you made about optional
parameters being added on the end is the only one that might sway me
to think otherwise, but currently we don't have any such parameters.
So, I'm not convinced this is not the way to go.

Bill Kempf


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