Re: Determining what prototype should be used for an object

On Nov 14, 2014, at 10:04 AM, Boris Zbarsky wrote:

> On 11/14/14, 11:46 AM, Allen Wirfs-Brock wrote:
>> (it isn't totally clear to me what you mean by the "current Realm".
> 
> I mean the ES6 meaning.
> 
>> (the above is actually conceptually true, but is glossing over how
>> constructors actually work.  Most object aren't directly associated with
>> a realm but the built-in prototype objects are.  Constructor function
>> simply set the [[Prototuype]] of the new instance to the current value
>> of the constructors `prototype `property`.
> 
> This covers cases when objects are created with constructors.  However, lots of objects in the ES spec are created with direct ObjectCreate/ArrayCreate bits that explicitly pass in the proto to use, and often use one of the standard built-in prototypes for the current Realm.

this is the case I was talking about when I said: "When an Object is directly created by some sort of factory ...".  The "factory" is the function that calls ObjectCreate, etc.  The explicitly passed proto is generally identified using %foo% notation which means 'foo' from the current realm.

(when ready the ES6 spec, it is import to know that "current realm" is associated with function objects, not with abstraction operations.  There may be a long chain of abstract operation calls starting with the body of a function.  That chain  of abstract operation calls don't change the current execution context and the "current realm" is that of the originating function.

> 
> Web IDL at the moment (somewhat implicitly) has a similar creation mechanism, whereby when an object is initially created you need to pass in the appropriate standard prototype from some Realm.  The question is what Realm.
> 
>>> But in ES it's also not common for built-in functions to create
>>> objects and keep returning them, for what it's worth.
>> 
>> I'm not sure what you mean here and why it is relevant. Could you elaborate.
> 
> Sure.  Consider the HTMLCanvasElement.prototype.getContext API. This is explicitly documented to have behavior that's described by something like the following pseudocode, with "arg" being the single argument to getContext:
> 
>  if (!this.[[CurrentContextType]]) {
>    this.[[CurrentContextType]] = arg;
>    this.[[CachedContext]] = InternalCreateContext(arg);
>  } else if (this.[[CurrentContextType]] != arg) {
>    // return null or throw, depending on this.[[CurrentContextType]]
>  }
>  return this.[[CachedContext]];

ok, I get it.  It's essentially an lazy accessor as the set of contexts could conceptually have been pre-populated with all possible context types when  the HTMLCanvasElement was instantiated.  If you think about it this way, then I would expect that all of the context values would be associated with the same realm as the HTMLCanvasElement instance.

> 
> The point being that the first call with a given argument caches the value to be returned and this value is returned every time after that.
> 
> Now it seems to me to be a bit weird for the prototype of the return value to depend on who has previously called this method and whether they called it directly or via .call/.apply.  So it makes some sense to define the return value's initial prototype in a way that's independent of the Realm of the getContext function, and instead in some way tied to the HTMLCanvasElement object itself.

right, it shouldn't depend upon any of those things, and if you weren't doing lazy construction it wouldn't.  Because you are doing lazy construction you probably need to explicitly capture the original HtMLCanvasElement realm and explicitly (internally) use it when creating the internal context objects.  This seems to be primarily a matter of ensuring consistency given this style of lazy creation and the various quarks of multiple realms plus apply/call. I don't think it says a lot about normal factory objects.

> 
> The other quirk here is that APIs like this are fairly common in browsers in practice, since lots of objects are lazily created in implementation terms, even if in spec terms many of them are expected to exist for the lifetime of the global (unlike this case, where the spec requires lazy creation).  So browsers have to have ways of lazily creating objects while making it look like they existed since the Realm was created (and hence have some canonical proto from that Realm at the point when you _actually_ create them).
> 
> I suspect the combination of these two things is what leads to the current browser behavior, fwiw.
> 
> Anyway, back to the "lazily create and cache" issue, I'm not aware, at first glance of ES6 APIs that do that, but I didn't look very carefully.

I can't think of any right now.  We would probably look at this as an implementation level optimization and expect such optimizations to preserve the specified semantics of ahead of time allocation.


Allen

Received on Friday, 14 November 2014 18:49:23 UTC