Re: [WebIDL] Simplify callbacks

On Wed, Dec 14, 2011 at 9:15 PM, Jonas Sicking <jonas@sicking.cc> wrote:

> On Wed, Dec 14, 2011 at 4:35 PM, Ian Hickson <ian@hixie.ch> wrote:
> > On Wed, 14 Dec 2011, Cameron McCormack wrote:
> >>
> >> Either we embrace object-with-property for all APIs that take callbacks,
> >> giving them meaningful method names, or we decide that all future APIs
> >> take only Functions.  Allowing object-with-property for new APIs but
> >> using handleEvent for them all seems like a sucky compromise to me.
> >
> > I think that the sucky situation would be to have lots of places that
> take
> > callbacks, but have to keep looking up what the heck the function is
> > called in order to use the object form.
> >
> > Consider an API that you can use whenever a callback is needed to track
> > the number of calls to the callback. If every callback uses a different
> > function name, you'd have to tell this API what the context of the
> > callback was instead of just being able to use it blindly. Consider what
> > it would take to change the implementation of such an API from using
> > closures to using an object to store data. Suddenly, every call site
> would
> > need to be updated to provide the callback method name.
> >
> > Don't think of "handleEvent" as meaning "handle a DOM Event object".
> Think
> > of it as "handle an event", the event being "the callback was invoked".
> > There's plenty of precedent for callbacks being called "HandleEvent".
>
> We have at least 3 options here:
>
> 1. Accept only Functions (except where webcompatibility requires otherwise)
> 2. Accept Functions and objects with a handleEvent function
> 3. Accept Functions and objects with a descriptive function name.
>
> If the callback has the same name everywhere then it adds absolutely
> no value over simply accepting only functions. People would end up
> having to write code like
>
> x = {
>  handleEvent: function(args) {
>    if (... detect first callback type based on args ...) {
>      doStuff();
>    }
>    if (... detect second callback type based on args ...) {
>      doOtherStuff();
>    }
>    etc;
>  },
>  doStuff: function() {...},
>  doOtherStuff: function() {...},
>  moreProps: "here"
> }
>
> registerCallbackFunc(x);
> registerOtherCallbackFunc(x);
>
>
> Compare this to:
>
> x = {
>  doStuff: function() {...},
>  doOtherStuff: function() {...},
>  moreProps: "here"
> }
>
> registerCallbackFunc(function() { x.doStuff() });
> registerOtherCallbackFunc(function() { x.doOtherStuff() });
>
> The latter is much cleaner and understandable. Not to mention that the
> first pattern doesn't work at all if you can't tell the types of
> callbacks apart based on what arguments they are given.
>
> So for the sake of not introducing useless features, I would say that
> 1 is strictly better than 2. That way people can use Function.bind and
> direct callbacks directly to where they want.
>
>
> However I think 3 has value in that it allows you to create a single
> object which listens to callbacks from many different APIs.
>
> x = {
>  onCallbackFunc: function() {...},
>  onOtherCallbackFunc: function() {...},
>  moreProps: "here"
> };
>
> registerCallbackFunc(x);
> registerOtherCallbackFunc(x);
>
>
> I don't think that having to memorize the callback names will be any
> worse having to remember any other names in the DOM. I think the DOM
> would be an even worse API if we renamed all functions to "function"
> and all the properties to "property".
>

I don't see the value in option 3. I have yet to see an example where
option 3 gives you something meaningfully better than just passing a
function. It's complexity without significant benefits.

My preference would be to do option 1, but I'd also be OK with option 2
because we want to be consistent across the platform and we can't kill
handleEvent on the old APIs. At some level, option 2 is more simple because
it means all these APIs can be handled with the same code in
implementations.

Received on Thursday, 15 December 2011 23:31:19 UTC