- From: Anselm R Garbe <garbeam@gmail.com>
- Date: Wed, 28 Apr 2010 14:01:31 +0100
- To: Robin Berjon <robin@robineko.com>
- Cc: public-device-apis@w3.org
On 28 April 2010 13:55, Robin Berjon <robin@robineko.com> wrote: > On Apr 28, 2010, at 12:04 , Anselm R Garbe wrote: >>> WDYT? >> >> I agree with Andrei. Can't see why your current situation is more complex. > > Throughout the stack there is greater variety than if we were considering the design of a single API (just because each API is independent doesn't mean we shouldn't look at the ecosystem, and more specifically at how hard it would be for someone to learn all of them). > > First, we have a number of such calls that only require the callbacks (e.g. DeviceFilesystem::filesystems). That's simple, you just have: > > #0 > PendingOp foo (FooCB successCB, optional ErrCB errorCB); > > Now you introduce required parameters (e.g. LocalFilesystem::requestTemporaryFilesystem). There are essentially three ways you can place them: > > #1 > PendingOp foo (DOMString foo, FooCB successCB, optional ErrCB errorCB); > > This loses the habit from #0 where you always start with the callbacks but it avoids the issues with the other three here. To address that we could frontload all parameters (so that the two callbacks are always last). > > #2 > PendingOp foo (FooCB successCB, optional ErrCB errorCB, DOMString foo); > > This maintains the "callbacks first" approach but since the error callback is option, the required string foo is (as per WebIDL) optional too. We can enforce it back in prose, but that means that the common case becomes obj.foo(sucCB, null, "foo") which is very annoying. > > #3 > PendingOp foo (FooCB successCB, DOMString foo, optional ErrCB errorCB); > > This maintains the required factor, but breaks up the callbacks. > > > The alternative is to put anything that isn't a required parameter into an options object. The same positional permutations are possible, and this is what happens: > > #1 works for methods for which you have a required option, but for those that only have optional options you end up with obj.foo(null, sucCB) or obj.foo({}, sucCB). Neither is nice. > > #2 and #3 have the exact same problems as above. > > > We then to other alternatives. One options is to realise that since the error callback is optional, it should go into the options such that we have: > > PendingOp foo (FooCB successCB, optional FooOptions options); > > This can be used consistently for all of our APIs, but it has the downside that this looks weird: obj.foo(sucCB, { error: errCB}). > > And then there's overloading: > > PendingOp foo (FooCB successCB, FooOptions options); > PendingOp foo (FooCB successCB, optional ErrCB errorCB, optional FooOptions options); > > But we'd have to put that everywhere, incurring lesser readability and more testing. > > Finally there's the do-nothing option (which is what we have today) whereby each asynchronous call does it its own way. This has the downside that you always have to look up the documentation to know which variant to use. I know people will write wrappers for this stuff, but it doesn't mean that we *have* to make it hard to use. > > In contrast, for the object literal approach: > > - consistency: check > - easy to memorise: check > - issues listed above: none > One idea I proposed originally in BONDI was having all callbacks at the end of functions: void func(options, [successCB, [errorCB]]); The advantage would have been that an implementation would have been able to react sync or async depending of the arguments passed in (eg if no CBs passed in, it could have done the operation synchronously). This proposal was dropped though because the W3C geolocation API was already there and defined callbacks as first arguments. Following your argumentation I couldn't resist to at least list this old proposal for the discussion. ;) Cheers, Anselm
Received on Wednesday, 28 April 2010 13:02:04 UTC