Re: Exposing constructors of readonly interfaces to web authors

On Jul 10, 2014, at 4:57 PM, "Rik Cabanier" <cabanier@gmail.com<mailto:cabanier@gmail.com>> wrote:




On Wed, Jul 9, 2014 at 4:54 AM, Domenic Denicola <domenic@domenicdenicola.com<mailto:domenic@domenicdenicola.com>> wrote:
From: Rik Cabanier <cabanier@gmail.com<mailto:cabanier@gmail.com>>

> This confirms that the current behavior can be implemented using JavaScript.
> Doesn't this satisfy Domenic's requirement?

It does, indeed, and gives us a path forward. However, in doing so, it points out that what the spec specifies is nowhere close to what was implemented. Here is a sketch of how we could update the specification to match what is (observably) going on:

- DOMRectReadOnly contains a [[type]] internal slot, which is either "quadbounds" or "rect"
- The x getter on DOMRectReadOnly returns either [[x]] if [[type]] is "rect", or the minimum of q.p1.x, q.p2.x, q.p3.x, and q.p4.x if [[type]] is "quadbounds". Similarly for y, width, and height.
- DOMRectReadOnly's constructor then needs to have two different behaviors (which could be based on arguments, or on e.g. the first parameter): one that sets the [[type]] slot to "quadbounds" and the [[quad]] slot to the given quad, and one that sets the [[type]] to "rect" and sets the [[x]], [[y]], [[width]], and [[height]] slots.
- DOMRect derives from DOMRectReadOnly.
  - It has a single constructor, (x, y, width, height), which calls super(x, y, width, height) (or super("rect", x, y, width, height), perhaps).
  - It has its own getters and setters for manipulating [[x]], [[y]], [[width]], and [[height]].
  - Thus DOMRects will always have [[type]] "rect", which means that you can successfully apply DOMRectReadOnly's getters to it, as you would expect for an inheritance situation.

I sketched this up, in a similar fashion to the previous one: https://gist.github.com/domenic/60871738e49a2b8c7a01

If this looks kind of weird, that's because it is. In general JS programmers would not write code this way. But, we are trying to meet many constraints here that JS programmers would not normally attempt, e.g. readonly views, reusing the same code for both live quad-bounds and one-time readonly snapshots, having a common prototype that can be monkeypatched by user code, and the like.

This seems to address Roc's concerns, though, and at least it is something that can be implemented (and introspected) in JavaScript.

All righty then, what do we think this time around?

After talking to Domenic, maybe we should rethink the DOMRect and DOMRectReadOnly classes.
Neither has functions and there is little value in them having a unique type or even an inheritance structure.

We actually want to extend the interfaces and add functionalities like intersections, unions and more on the future. Beside, I think we already got to an consensus and we need to figure out the right wording. No need to redesign the whole interface into an not extensible, not instance based dictionary.

Also, this would just apply to DOMRect but not to DOMPoint or DOMMatrix. Better to find a general solution.

Greetings,
Dirk


What if instead of interfaces, we just define them as dictionaries:
dictionary DOMRect {
unrestricted double x;
unrestricted double y;
unrestricted double width;
unrestricted double height;
readonly unrestricted double top;
readonly unrestricted double right;
readonly unrestricted double bottom;
readonly unrestricted double left;
};

dictionary DOMRectReadOnly {
readonly unrestricted double x;
readonly unrestricted double y;
readonly unrestricted double width;
readonly unrestricted double height;
readonly unrestricted double top;
readonly unrestricted double right;
readonly unrestricted double bottom;
readonly unrestricted double left;
};

a prototype implementation of DOMQuad would then look as follows:
function DOMQuad(p1, p2, p3, p4){
    this.p1 = new DOMPoint(p1);
    this.p2 = new DOMPoint(p2);
    this.p3 = new DOMPoint(p3);
    this.p4 = new DOMPoint(p4);
    this.bounds = {};
    var self = this;

    Object.defineProperty(this, "p1", { writable : false });
    Object.defineProperty(this, "p2", { writable : false });
    Object.defineProperty(this, "p3", { writable : false });
    Object.defineProperty(this, "p4", { writable : false });
    Object.defineProperty(this, "bounds", { writable : false });

    Object.defineProperty(this.bounds, 'left', { enumerable: true,get: function() {
    return Math.min(Math.min(self.p1.x, self.p2.x), Math.min(self.p3.x, self.p4.x));
    } });

    Object.defineProperty(this.bounds, 'top', { enumerable: true,get: function() {
    return Math.min(Math.min(self.p1.y, self.p2.y), Math.min(self.p3.y, self.p4.y));
    } });

    Object.defineProperty(this.bounds, 'right', { enumerable: true,get: function() {
    return Math.max(Math.max(self.p1.x, self.p2.x), Math.max(self.p3.x, self.p4.x));
    } });

    Object.defineProperty(this.bounds, 'bottom', { enumerable: true,get: function() {
    return Math.max(Math.max(self.p1.y, self.p2.y), Math.max(self.p3.y, self.p4.y));
    } });

    Object.defineProperty(this.bounds, 'x', { enumerable: true,get: function() {
    return this.left;
    } });

    Object.defineProperty(this.bounds, 'y', { enumerable: true,get: function() {
    return this.top;
    } });

    Object.defineProperty(this.bounds, 'width', { enumerable: true,get: function() {
    return this.right - this.left;
    } });

    Object.defineProperty(this.bounds, 'height', { enumerable: true,get: function() {
    return this.bottom - this.top;
    } });
}

Received on Thursday, 10 July 2014 15:54:29 UTC