Perhaps @@unscopable shouldn't be a Set...

# Allen Wirfs-Brock (12 years ago)

At last weeks TC39 meeting we had consensus that the value of the @@unscopable property should be a Set rwaldron/tc39-notes/blob/master/es6/2013-09/sept-17.md#53-unscopeable

As I begin to look at implementing this (and the other @@unscopable changes from the meeting) I'm not so sure that Set is such a good idea. My basic concern is that @@unscopable operates at a very low level of the ES name binding resolution mechanism. Set exists at a much higher conceptual level of the ES library and (until now) there was nothing in the fundamental language semantics of ES that depends upon the existence of a library Set object. Now that I have thought about this, it seems fundamentally wrong to unnecessarily create such an up-dependency.

I think we will have a cleaner semantics if we continue to treat an @@unscopable value as an array-like object for the purpose of accessing its property blacklist. Implementations, if they wish, can us2 caching scheme to obtain sub-linear time access to an @@unscopable blacklist.

In light of this consideration, does anybody still want to argue that we should require an @@unscopable value to be a Set instance?

# Erik Arvidsson (12 years ago)

Conceptually it is a set but I don't think anyone cares enough to oppose this being an array given that it is a cleaner layering of the spec.

# Andreas Rossberg (12 years ago)

I sympathise with Allen's concern. Implementations might have layering issues as well, especially if Set is mostly self-hosted. We should make it a plain array.

# Rick Waldron (12 years ago)

On Wed, Sep 25, 2013 at 5:41 PM, Andreas Rossberg <rossberg at google.com>wrote:

I sympathise with Allen's concern. Implementations might have layering issues as well, especially if Set is mostly self-hosted. We should make it a plain array.

Agreed. I originally had thought there might be benefit in the implicit uniqueness, but it's not compelling.

# Allen Wirfs-Brock (12 years ago)

So here is another concern, about the scheme we agreed to last week.

It needs to match a found own property against the possibility of an own @@unscopable property on the same object and that object may be somewhere up the inheritance chain of the actual with object. The means that [[HasProperty]]/[[Get]]/[[Set]] can not be used to do those resolve binding in an ObjectEnvironmentRecord because they don't tell us where the property was found. Instead, ObjectEnvironmentRecord needs to reimplement its own property lookup using [[GetOwnProperty]] and [[GetInheritanceOf]]. However, if the with object is a proxy that means we may be bypassing the actual inheritance mechanism implemented by the Proxy's 'has'/'get'/'set' traps and that could introduce observable semantics irregularities.

Specifying the duplicated lookup is doable but a pain. That and the semantic issues WRT proxies makes me a lot less comfortable with the added complexity of supporting @@unscopable.

# Erik Arvidsson (11 years ago)

This was never resolved and the spec is incomplete here

# Axel Rauschmayer (11 years ago)

Specifying the duplicated lookup is doable but a pain. That and the semantic issues WRT proxies makes me a lot less comfortable with the added complexity of supporting @@unscopable.

I never liked it. It burdens the language in order to support legacy code. Are there other ways of fixing the problem?

A few, probably silly, ideas, for the sake of brainstorming:

  • Hard-coding with to ignore only Array.prototype.values.
  • Patching the problematic libraries somehow.
  • Use a property attribute to signal to with that a property should be ignored. [[Enumerable]] would be perfect, but unfortunately won’t work.

Somehow, we have to put the burden on with and the legacy code instead of the future-facing parts of the language.

Axel

# Rick Waldron (11 years ago)

On Wed, Apr 30, 2014 at 1:14 PM, Axel Rauschmayer <axel at rauschma.de> wrote:

Specifying the duplicated lookup is doable but a pain. That and the semantic issues WRT proxies makes me a lot less comfortable with the added complexity of supporting @@unscopable.

I never liked it. It burdens the language in order to support legacy code. Are there other ways of fixing the problem?

A few, probably silly, ideas, for the sake of brainstorming:

Here's the conversation, everything in your list was discussed: rwaldron/tc39-notes/blob/master/es6/2013-07/july-23.md#43-arrayprototypevalues

  • Hard-coding with to ignore only Array.prototype.values.

@@unscopables is this, but not limited to Array.prototype.values

  • Patching the problematic libraries somehow.

This is not reasonably feasible when the libraries are being used in enterprise applications and are done so under contract/license (as in the case of Ext.js)

  • Use a property attribute to signal to with that a property should be ignored. [[Enumerable]] would be perfect, but unfortunately won’t work.

Andreas suggested this originally, but the additional state bit on every object is undesirable.

Somehow, we have to put the burden on with and the legacy code instead of the future-facing parts of the language.

That's what @@unscopables does.

# Erik Arvidsson (11 years ago)

On Wed, Apr 30, 2014 at 1:22 PM, Rick Waldron <waldron.rick at gmail.com>wrote:

On Wed, Apr 30, 2014 at 1:14 PM, Axel Rauschmayer <axel at rauschma.de>wrote:

  • Hard-coding with to ignore only Array.prototype.values.

My main use case for unscopable is for DOM. Today we cannot add nice named methods to Element or any of its superclasses since HTML attribute event handlers uses ObjectEnvironments.

From Web Animation spec

interface Animatable { AnimationPlayer animate (object? effect, optional (double or TimingInput) timing); ... }

Element implements Animatable;

This means that any HTML attribute event handler that tries to call a global function called animate are now broken.

@unscopable allows us to have nice things.

# Brendan Eich (11 years ago)

Including Tom because proxies and MOP.

# Axel Rauschmayer (11 years ago)

My main use case for unscopable is for DOM. Today we cannot add nice named methods to Element or any of its superclasses since HTML attribute event handlers uses ObjectEnvironments.

So Element.prototype is in the variable scope chain of event handlers? Wow. Is this documented somewhere?

Thanks!

Axel

# Boris Zbarsky (11 years ago)

On 4/30/14, 2:49 PM, Axel Rauschmayer wrote:

So Element.prototype is in the variable scope chain of event handlers? Wow. Is this documented somewhere?

You mean other than in the spec? See www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#getting-the-current-value-of-the-event-handler step 10.

Note that it's not Element.prototype that's in the scope chain but the element itself. It's just that the property lookup on the element will walk its proto chain.

# Axel Rauschmayer (11 years ago)

On 30 Apr 2014, at 21:17 , Boris Zbarsky <bzbarsky at mit.edu> wrote:

On 4/30/14, 2:49 PM, Axel Rauschmayer wrote:

So Element.prototype is in the variable scope chain of event handlers? Wow. Is this documented somewhere?

You mean other than in the spec? See www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#getting-the-current-value-of-the-event-handler step 10.

Thanks, wasn’t able to find it. Not pretty.

# Allen Wirfs-Brock (11 years ago)

Where do you find the spec incomplete WRT @@unscopable. My recollection was that it was all resolved and fully specified and that I was relatively happy with the outcome.

# André Bargull (11 years ago)

Where do you find the spec incomplete WRT @@unscopable. My recollection was that it was all resolved and fully specified and that I was relatively happy with the outcome.

unscopables for the Object Environment Record is always the empty list. It's never populated.

# Erik Arvidsson (11 years ago)

On Wed, Apr 30, 2014 at 5:17 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

Where do you find the spec incomplete WRT @@unscopable. My recollection was that it was all resolved and fully specified and that I was relatively happy with the outcome.

I thought so too but now that I look at it I cannot find where we Get the @unscopable list out of the with expression object. As far as I can tell unscopables is never populated.

people.mozilla.org/~jorendorff/es6-draft.html#sec-with-statement-runtime-semantics-evaluation, people.mozilla.org/~jorendorff/es6-draft.html#sec

# André Bargull (11 years ago)

The changes from ecmascript#1908 never made it into the spec.

# Erik Arvidsson (11 years ago)

The algorithms in the spec bug uses an object and HasOwnProperty check instead of an array and looping from 0 to length - 1. That has a lot of benefits since there are less things that can go wrong (no getters, no toString etc).

However, we might want to change to use HasProperty instead of HasOwnProperty, and have a null prototype Object for Array.prototype[Symbol.unscopables]. The reason is that would make it easier to make these more contained.

For example, in the DOM world we want to add append to Node [*] and animate to Element. If we used HasProperty we could do something like

Node.prototype[Symbol.unscopable] = {
  __proto__: null,
  append: true
};

Element.prototype[Symbol.unscopable] = {
  __proto__: Node.prototype[Symbol.unscopable],
  animate: true
};

If we used HasOwnProperty we would either need to change a subclass when a superclass changes or we would need to do the more complicated solution with manually walking the prototype chain in ObjectEnvironment HasBinding.

[*] not entirely true, it would go on the ParentNode interface

# Allen Wirfs-Brock (11 years ago)

The correct code was in rev21, but somehow got lost in rev22 and later. What is currently in the spec. is essentially what was in rev20.

# Claude Pache (11 years ago)

The algorithm given in Bug 1908, comment 2 is problematic, as a property name blacklisted by an @@unsopables anywhere on the prototype chain will also be blacklisted when it appears as own property of the object itself, which is undesirable. According to the meeting notes of Sep 2013 meeting, this issue was discussed, but it appears that the algorithm presented in Bug 1908 does not incorpore the needed correction.

The algorithm for HasBinding(N) on an object environment record should be (and it seems to have been suggested in the Consensus/Resolution section of the meeting notes, if I interpret it correctly):

  1. First, check if there is a property of name N in the prototype chain, using HasProperty();
  2. then, if the property of name N is found and if the withEnvironment flag is set to true, look for an own @@unscopables property on the object of the prototype chain where the property of name N was found, and see if it is blacklisted there.

(I was first tempted to say that, if the property name is blacklisted, we could continue to walk deeper in the prototype chain to see if we find a non-blacklisted one; but we should not do that, as it would lead to complications on the algorithms that effectively get, set or delete such a property.)

(one more comment below)

Le 1 mai 2014 à 01:23, Erik Arvidsson <erik.arvidsson at gmail.com> a écrit :

The algorithms in the spec bug uses an object and HasOwnProperty check instead of an array and looping from 0 to length - 1. That has a lot of benefits since there are less things that can go wrong (no getters, no toString etc).

However, we might want to change to use HasProperty instead of HasOwnProperty, and have a null prototype Object for Array.prototype[Symbol.unscopables]. The reason is that would make it easier to make these more contained.

For example, in the DOM world we want to add append to Node [*] and animate to Element. If we used HasProperty we could do something like

Node.prototype[Symbol.unscopable] = {
  __proto__: null,
  append: true
};

Element.prototype[Symbol.unscopable] = {
  __proto__: Node.prototype[Symbol.unscopable],
  animate: true
};

If we used HasOwnProperty we would either need to change a subclass when a superclass changes or we would need to do the more complicated solution with manually walking the prototype chain in ObjectEnvironment HasBinding.

[*] not entirely true, it would go on the ParentNode interface

With my proposed algorithm, you just need to blacklist unscopable properties on the same object where they are defined:

Node.prototype.@@unsocopables = { append: true }
Element.prototype.@@unsocopables = { animate: true }
# Andreas Rossberg (11 years ago)

On 2 May 2014 14:45, Claude Pache <claude.pache at gmail.com> wrote:

The algorithm given in [Bug 1908, comment 2] (ecmascript#1908#c2) is problematic, as a property name blacklisted by an @@unsopables anywhere on the prototype chain will also be blacklisted when it appears as own property of the object itself, which is undesirable. According to the [meeting notes of Sep 2013 meeting] (rwaldron/tc39-notes/blob/master/es6/2013-09/sept-17.md#53-unscopeable), this issue was discussed, but it appears that the algorithm presented in Bug 1908 does not incorpore the needed correction.

The algorithm for HasBinding(N) on an object environment record should be (and it seems to have been suggested in the Consensus/Resolution section of the meeting notes, if I interpret it correctly):

  1. First, check if there is a property of name N in the prototype chain, using HasProperty();
  2. then, if the property of name N is found and if the withEnvironment flag is set to true, look for an own @@unscopables property on the object of the prototype chain where the property of name N was found, and see if it is blacklisted there.

Yes, we discussed all this at the September meeting, and the consensus was to refine the algorithm in the very way you suggest.