Re: Web IDL attributes and delegation

Replies inline.

On 2012-09-12 11:34, Boris Zbarsky wrote:
> On 9/12/12 4:38 PM, Colin Snover wrote:
>> As a JS author, it is important to me to be able to have a way to
>> augment DOM event objects and/or override certain properties (which may
>> be defined as readonly) in a time- and memory-efficient manner.
>
> In a browser that implements WebIDL as written, this can be
> accomplished by simply defining properties on the event object, right?

So, two things I guess.

First, there seems to be an assumption here that I want to permanently
alter the original event object. Sometimes this is OK, but sometimes it
is not. I can think of several instances where I would prefer having a
delegate object, mostly in cases where it was deemed important that the
original object not be modified directly because it would be used again
in the future (e.g. using the same platform Event object to fire unique
but related fake events in order to provide abstraction over
touch/pointer/mouse APIs to end-user code, if that description makes
sense). As a general rule, I prefer not to touch platform objects
directly when possible anyway.

Second, if I am reading the spec correctly, [Unforgeable] means
defineProperty *won’t* work in some cases. This flag may not be set on
Event properties, but frankly, I don’t trust W3C WGs *or* browser
vendors enough to assume that it won’t be used on some property that I
need to replace in the future. At least if it is possible to use
platform objects as prototypes I know there is one way to relatively
efficiently escape this situation.

>> Right now, most script libraries end up doing a shallow copy of
>> properties
>> from the native event object to a surrogate and then fix up the standard
>> event methods (stopPropagation, etc.) to point back to the native
>> object, which is quite inefficient, and can be especially bad for
>> performance when dealing with high-volume events (touchmove, mousemove,
>> etc.). Delegation via e.g. Object.create should be a more reasonable way
>> to accomplish this
>
> I'm trying to understand why a separate object is needed at all.  Is
> this just working around the fact that some implementations put IDL
> attributes directly on the object, not on the prototype?

No, though it sounds like using defineProperty would break these
implementations now. Do you know offhand who implements this way and if
this does, indeed, break them?

>> I strongly believe that browser vendors should be making every effort
>> to make
>> host/platform objects indistinguishable from native JavaScript objects
>> as much as possible
>
> Let's stop and do a thought experiment.

OK.

> Say you implement the innerHTML getter that lives on
> HTMLElement.prototype in JavaScript.  Assume that your DOM is in fact
> implemented as native JavaScript objects (so your DOM nodes are native
> objects), but complies with the DOM specification.
>
> Now say a web page does:
>
>   var elem = document.createElement("span");
>   elem.innerHTML = "<i>Something</i>"
>   var obj = Object.create(elem);
>   Object.defineProperty(obj, "firstChild", { value: elem; });
>   alert(obj.innerHTML);
>
> What should happen and why?

Line 1 creates a new DOM object as elem and initialises it. Line 2
causes elem to create an internal DOM structure representing the
provided string. Line 3 creates a new object using elem as its
prototype. Line 4 sets the firstChild property of the object obj to
elem. Line 5 calls elem’s innerHTML getter and alerts the result, which
should be the same value provided in line 2, because Line 4 just defined
a new property on obj (and firstChild is readonly, but even if it
wasn’t, the firstChild setter would not be called because [[Put]] was
not used).

>> entertained, would be to fix the |this| value of platform object
>> getter/setters to the platform object itself
> My first thought for an alternative proposal, were one to be
>
> Which particular platform object?  Note that the getters live on the
> prototype, not on the platform object itself.

In your previous example, the elem object. I realise that this is
probably ugly from an implementation perspective but the current
proposal is almost certainly worse from an authoring perspective.

>> whilst still allowing
>> read-only properties to be safely redefined on the delegate.
>
> Again, this can already be done with Object.defineProperty in UAs that
> actually implement WebIDL.

Well, it can’t, or else we wouldn’t be having this discussion. :) The
editor’s draft currently says an error must be thrown if |this| is not a
platform object, so it is possible to either redefine *on the platform
object itself* (if it’s allowed by the interface), *or* it is possible
to create a perfectly worthless delegate object where only accessing
overridden properties works. It is not possible to create a delegate to
a platform object and have things function in a somewhat sane manner.

Cheers,

-- 
Colin Snover
http://zetafleet.com

Received on Thursday, 13 September 2012 01:39:53 UTC