Boost logo

Boost :

From: Douglas Gregor (gregod_at_[hidden])
Date: 2000-11-22 14:19:16


On Wed, 22 Nov 2000 10:06:32 -0800
Karl Nelson <kenelson_at_[hidden]> wrote:

[snip]
> > 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.
>
> 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.)

The error messages may be uglier, but they are still easily decipherable. In any case, I don't believe the ugliness of the error messages outweighs the benefits of having a more clean, consistent interface for correct cases.

>
> 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) { ... }
> ...
> };

The callback class doesn't have to implement all operator() overloads, though the alternative requires deriving from a base class which has the proper overload. The first option is slightly more readable for the "callback" class itself, the second option gives the best error messages (since only one operator() exists).
 
>
> 3) It only saves one charactor. :-) The same things could be achieved

Yes, it is only one character, but it's an extra parameter that is implied. How would a programmer new to the callback library interpret callback0, callback1, etc? Omitting the number makes all callbacks look the same, and excludes extra information which could be confusing.

> 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);
> };
>
> Which insidentally extracts with VC++ and other code browsers
> to make more sense.

I apologize, but I'm not seeing how this would be achieved.
 
> 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.)

Default constructible isn't be a problem in general, it was just a result of that implementation.

> 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!)

This is most definitely a problem, and the major drawback of this approach.

> 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.

Not necessarily. In my original event library, I used this technique and had scripts to generate the event classes. The only reason this has yet to be done for any of the current callback library candidates is that it is less manageable in the prototype stage.

> 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.

I've added support for VC++ to my own callback prototype, and overall the code is quite readable (see the "Callback" folder on egroups). Indeed, the partial specialization via member templates trick is a bit tedious, but I doubt there is much more code than for the equivalent callback[0-3] classes.

> For all of these reasons SigC went with numbered classes.
> I hope you consider carefully these reasons before chosing to do
> differently.

        Doug Gregor


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