RE: Exposing constructors of readonly interfaces to web authors

Thanks for the reply; I appreciate the focus on intent. Unfortunately there are still a number of problems and mismatches between the intent and what’s going on in the spec. I'm hopeful we can get to the bottom of it.

From: rocallahan@gmail.com [mailto:rocallahan@gmail.com] On Behalf Of Robert O'Callahan

> We have a DOMQuad, whose state is mutable in various ways. We want to expose a view of its state, the bounding rectangle. This view must be read-only (since it doesn't make sense to mutate the bounding rect directly).

"doesn't make sense" and "must be disallowed" are two very different things. The conventional way of exposing a view in JavaScript is to expose a snapshot object, which is just a plain object (with Object.prototype as its prototype, not a custom class) and data properties, instead of getters. In this case the "computed properties" top, right, bottom, and left are best off as getters, which could be put on a common prototype, and so a plain object is not necessary. But there is still no reason to make the x, y, width, and height themselves immutable, at least in the general case of a view onto a rectangle (i.e. a generic DOMRect or DOMRectReadOnly class).

> Since this view is a rectangle, for consistency we want to expose it as some kind of readonly rectangle object matching, as much as possible, the API of the mutable rectangle objects returned by other DOM APIs. It seems more natural to expose this view as an attribute than via a method getter,

Agreed.

> and that means repeated gets on the same DOMQuad must return the same object

Not necessarily. The important invariant is `quad.bounds === quad.bounds`. It is not important that:

var b1 = quad.bounds;
doAnythingAtAll();
var b2 = quad.bounds;
assert(b1 === b2); // this does NOT have to hold.

> In any imperative OO language I know of, this is easy to implement. The bounds object keeps a hidden reference to the DOMQuad and implements its readonly APIs as functions of the DOMQuad state, and the DOMQuad keeps an reference its bounds object.

So, notably, this is not compatible with the APIs in the spec, where there is no such hidden reference to the DOMQuad. The bounds object is a simple DOMRectReadOnly, and is not constructed with any such internal linkages.

> As far as I can tell, this is implementable in JS too, using getters in the prototype:
>
> var quad = {x1:1, x2:2, x3:3, x4:4};
> function QuadBounds(q) {
>   this.q = q;
> }
> Object.defineProperty(QuadBounds.prototype, "left", {get:function() {
>   return Math.min(this.q.x1, this.q.x2, this.q.x3, this.q.x4);
> }});
> var b = new QuadBounds(quad);
> alert(b.left);
> So I don't actually know what the problem is here :-).

Well, if this was what was specified in the spec, we would have no problem! But instead we have this DOMRectReadOnly business, which has no constructor (and so instances of it cannot exist, modulo the unguessable-secret technique), and no reference to the DOMQuad, and has properties like "left" that return min(x, x + width) for some value of "the x coordinate" and "the width" which are never set but only gotten.

I love the direction you are proposing, and I'd encourage either the use of mutable snapshots (as I propose above) or some kind of reification of what you propose into the spec.

In *either* case, I'd strongly suggest we draw up a prototype of whatever we're proposing in pure JavaScript, so that the semantics are clear and everyone understands how it works, without major gaps like objects that can't be constructed, or internal linkages that are never specified. A spec about geometry is more or less the perfect case for this, as there is nothing magical going on here that requires system-level APIs, but simply object modeling. I am happy to volunteer my time on this, both as an individual and as a member of the TAG, to help us reach a better spec. Indeed, if we can agree on how things *should* work, I can try to draw up a prototype we can look at together.

Received on Monday, 30 June 2014 01:44:48 UTC