Re: Exposing constructors of readonly interfaces to web authors

On 7/1/14, 6:16 PM, Domenic Denicola wrote:
> So if I understand correctly, you are saying that there are two different functions being run when I do (new DOMQuad()).bounds.x and when I do (new DOMRect()).x, but to JavaScript, since DOMQuadBounds has a different implementation than DOMRect. But it looks like they are the same function to JavaScript?
>
> How is this possible?

There are several things going on here.

First of all, the prototopy chains for (new DOMQuad()).bounds) and (new 
DOMRect()) look like this:

   (new DOMQuad()).bounds) -> DOMRectReadOnly.prototype

   (new DOMRect()) -> DOMRect.prototype -> DOMRectReadonly.prototype

In this case, there is a getter for the property named "x" on _both_ 
DOMRect.prototype and DOMRectReadonly.prototype.  So when you do

   (new DOMQuad()).bounds).x

and

   (new DOMRect()).x

you are not in fact calling the same JS function.

But that's an accident, more or less.  We could add a new property, call 
it "area" on DOMRectReadOnly.prototype that is not shadowed by DOMRect. 
  Getting .area on either of those objects would then call this same JS 
function.  What this JS function does in Gecko is extract the underlying 
C++ object (a DOMRectReadOnly in this case) and call a method on it.

It so happens that in Gecko the DOMRectReadOnly C++ object only has pure 
virtual functions.  That is, it delegates all calls on it to subclasses. 
  Internally, (new DOMQuad()).bounds) and (new DOMRect()) instantiate 
different subclasses of DOMRectReadOnly, that have functions named "X" 
that have different implementations.

So effectively, these two objects have an internal slot (the C++ vtable 
in this case, but you could do the same sort of thing in JS via symbols, 
say, or in C++ via a boolean member or some other polymorphism 
mechanism) that indicates what the getter should do when invoked with 
that sort of object as a this object.

Back to my "area" example, if we were to implement that, we would of 
course implement it directly on DOMRectReadOnly, not on subclasses, 
since all it needs is the already existing exposed API to compute its 
result..  So an "area" getter would not in fact be polymorphic.

I can't speak to the desirability of this behavior.  Polymorphic 
behavior via introspection of the this value is not super-common in JS 
(not least because introspection is complicated) but is not unknown.  In 
fact, a number of ES6 algorithms support just that sort of polymorphism 
by delegating various tasks this.something, which allows subclasses to 
override the default superclass implementation in certain well-defined ways.

-Boris

Received on Wednesday, 2 July 2014 03:10:54 UTC