Re: [UndoManager] Re-introduce DOMTransaction interface?

On Thu, Jul 12, 2012 at 12:38 PM, Jonas Sicking <jonas@sicking.cc> wrote:

> On Thu, Jul 12, 2012 at 2:07 AM, Yuval Sadan <sadan.yuval@gmail.com>
> wrote:
> >> I think we need to realize that a lot of the APIs that have been
> >> designed in the past aren't terribly good APIs.
> >
> > The IndexedDB API is rather new, and the manner in which it consistently
> > uses event handlers on returned objects is rather innovative. The
> > DOMTransaction object is more similar to that.
>
>
The IndexedDB pattern is rather an old one - see the Python (I know,
Ryosuke....) "Twisted" library which uses 'deferreds' which went on to
influence hundreds of projects in many languages. Eventually it migrated
into JS libraries as "promises" (sans a few subtle differences...)

I think the key difference between the two models (DOMTransaction vs
IndexedDB's events) is about the creation of the event-owning object. hen
you pass in a dictionary/DOMTransaction/etc, then the caller is is
responsible for creating that object and doesn't give the callee (i.e. the
API) a lot of control over the event propagation/etc. One thing IndexedDB's
IDBRequest object has going for it is that the implementation creates it,
therefore controls the behavior and the interaction between success, error,
and abort events.

One particularly nice thing the event pattern adds on top of the deferred
pattern is the ability to have multiple semantically parallel event
handlers, i.e.

// wrapper around get() to update something whenever we encounter purple
keys
function myGet(k) {
    r = objectStore.get(k)
    r.addEventListener(dealWithPurpleKeys);
    return r;
}
r = myGet(key);
r.addEventListener(dealWithThisKey);


If the DOMTransaction/dictionary has to be passed in, this complicates this
pattern quite a bit, and this is a pretty nice pattern in a dynamic
language like JS.

 In IndexedDB events work out "ok" since we can take advantage of the
> event bubbling mechanism. That's not the case here.
>
> Likewise, in IndexedDB you generally only have to install a single
> event handler, which means that you can write code like:
> store.get(...).onsuccess = function(event) { ... };
>
>
I would argue that you can do this easily in IndexedDB *because* of event
bubbling - or at least by the fact that there is a "parent" object (the
IDBTransaction) - you can let error propagation be handled by a "parent"
object so that you dont' have to install error handlers on every request.

Just watching this conversation, the way I'm seeing it is it's fairly easy
to make a wrapper API around the deferred/event model that looks like
Ryosuke's model, than it is the other way around. It also seems like if you
could add some kind of event handling (i.e. if a user had a kind of generic
undo-er method that worked on 90% of events, but then could attach specific
undoer-s to specific types of transactions)

(I personally come from the school of thought that the DOM APIs are kind of
the assembly language of the web - they're very powerful and exact, you can
use them in a pinch but most people won't use them directly and will put
some kind of higher level abstraction on top of them. I don't think this is
a failing of the APIs by any means, no more than the proliferation of
computer languages is a failing of CPUs)

Alec


> or
>
> store.get(...).onsuccess = obj.myhandler.bind(obj);
>
> Neither of which is possible here.
>
> Yet, in IndexedDB I would have strongly preferred to use promices
> rather than DOM-Events based Request objects. The only reason we don't
> is because there are no standardized promices that we can use.
>
> >> In other words, I think it's more important to focus on what makes a
> >> good API, than what is consistent with other DOM APIs.
> >
> > Consistency has its value. Even if some is lacking, fixing it in some
> places
> > and not in others might cause a jumble. Which is my feeling actually
> about
> > the IndexedDB API. Adding more syntactical variations can lead to hectic
> > code.
> > However, I agree that it's not the primary concern.
>
> Indeed.
>
> >> Something that I really liked about the old API was the fact that
> >> using it created very intuitive code. Basically you just write a class
> >> the way you normally would write a class, and then pass in your
> >> object:
> >>
> >> x = {
> >>   someState: 0,
> >>   apply: function() { this.someState++; this.modifyDOM(); },
> >>   unapply: function() { this.subState--; this.modifyDOMOtherWay(); },
> >>   ...
> >> };
> >> undoManager.transact(x);
> >>
> >>
> >> You can even do things like
> >>
> >> undoManager.transact(createParagraphTransaction(params));
> >
> > How's that different from:
> > function createParagrahTransaction(params) {
> >   x = new DOMTransaction("Create paragraph");
> >   x.apply = function() { ... use params... };
> >   x.onundo = function() { ... use params ... };
> >   return x;
> > }
>
> Ah, you can, but that still doesn't give you nice "class" syntax.
>
> What I actually meant to say was that you can't do something like:
>
> undoManager.transact(new ParagraphTransaction(params));
>
> > Also, in your example, I think that in the JS-object proposal you won't
> be
> > able to reference the original object's properties -- it will be lost,
> and
> > 'this' is window.
>
> Only if you use a dictionary, which I don't think we should. We should
> use an interface annotated with 'callback'.
>
> >> The fact that we have to choose between creating APIs that feel like
> >> "DOM APIs" or "JS APIs" I think is an indication that "DOM APIs" are
> >> doing things wrong. There should be no difference between "DOM APIs"
> >> and "JS APIs".
> >
> > It is a problem. But WebIDL and JS aren't two of the same.
>
> I agree. I don't believe I was arguing that it was. All solutions
> debated here can be described using WebIDL.
>
> / Jonas
>
>

Received on Friday, 13 July 2012 17:40:53 UTC