-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Normative: Permit Symbol as WeakMap key and WeakSet entry #2038
Conversation
(Marking as "ready for review" just with the hope that it shows up in https://arai-a.github.io/ecma262-compare/ . This should be understood to be a draft.) |
spec.html
Outdated
@@ -36582,7 +36582,7 @@ <h1>WeakMap.prototype.delete ( _key_ )</h1> | |||
1. Let _M_ be the *this* value. | |||
1. Perform ? RequireInternalSlot(_M_, [[WeakMapData]]). | |||
1. Let _entries_ be the List that is _M_.[[WeakMapData]]. | |||
1. If Type(_key_) is not Object, return *false*. | |||
1. If Type(_key_) is not Object or Symbol, return *false*. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure if this would be overkill, but it might be nice to have a single abstract operation that owns this definition instead of having to change it in 4-8 places
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I'm open to that. I guess the general question would be, do we want to define a term for this concept of being an Object or Symbol? For example, "referenceable" or "identity-full"? If someone can think of a real word describing this concept, that'd probably be better than those two...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
forgeable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
forgeable means something different :-)
"weakable" sounds weird tho
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say that the general concept is something like "distinguishable".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"distinguishable" might be a bit too broad, since 3 and 4 are distinguishable but depending on your mental model:
- if each
3
is a different 3, but3 === 3
compares them by value and not by identity/reference, then symbols and objects "have identity" but the rest don't. - if every
3
is the same 3, then you can create symbols and objects, but the rest are more like singletons referenced by syntax, in which case i'm not sure what you'd call symbols and objects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're going to be able to poke holes in whatever term we come up with; the key will be to socially agree on some shared language here. I could see using either "unforgeable" or "distinguishable" if we agreed on it, and adjusted our usages in other places appropriately. Other terms could also be fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HasIdentity
, perhaps? (It needn't be a single adjective.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if we used a phrase, "has identity"? We could still define and linkify this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer it as an abstract operation, personally, to match IsCallable
and friends. Don't feel strongly though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The spec text looks good to me; just a few minor suggestions regarding the prose.
spec.html
Outdated
@@ -36508,11 +36508,11 @@ <h1>Properties of Set Iterator Instances</h1> | |||
|
|||
<emu-clause id="sec-weakmap-objects"> | |||
<h1>WeakMap Objects</h1> | |||
<p>WeakMap objects are collections of key/value pairs where the keys are objects and values may be arbitrary ECMAScript language values. A WeakMap may be queried to see if it contains a key/value pair with a specific key, but no mechanism is provided for enumerating the objects it holds as keys. If an object that is being used as the key of a WeakMap key/value pair is only reachable by following a chain of references that start within that WeakMap, then that key/value pair is inaccessible and is automatically removed from the WeakMap. WeakMap implementations must detect and remove such key/value pairs and any associated resources.</p> | |||
<p>WeakMap objects are collections of key/value pairs where the keys are objects and/or symbols and values may be arbitrary ECMAScript language values. A WeakMap may be queried to see if it contains a key/value pair with a specific key, but no mechanism is provided for enumerating the objects and/or symbols it holds as keys. If an object or symbol that is being used as the key of a WeakMap key/value pair is only reachable by following a chain of references that start within that WeakMap, then that key/value pair is inaccessible and is automatically removed from the WeakMap. WeakMap implementations must detect and remove such key/value pairs and any associated resources.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should refer to "value being used as a key" rather than "object and/or symbol being used as a key".
<p>WeakMap objects are collections of key/value pairs where the keys are objects and/or symbols and values may be arbitrary ECMAScript language values. A WeakMap may be queried to see if it contains a key/value pair with a specific key, but no mechanism is provided for enumerating the objects and/or symbols it holds as keys. If an object or symbol that is being used as the key of a WeakMap key/value pair is only reachable by following a chain of references that start within that WeakMap, then that key/value pair is inaccessible and is automatically removed from the WeakMap. WeakMap implementations must detect and remove such key/value pairs and any associated resources.</p> | |
<p>WeakMap objects are collections of key/value pairs where the keys are objects and/or symbols and values may be arbitrary ECMAScript language values. A WeakMap may be queried to see if it contains a key/value pair with a specific key, but no mechanism is provided for enumerating the keys. If a value that is being used as the key of a WeakMap key/value pair is only reachable by following a chain of references that start within that WeakMap, then that key/value pair is inaccessible and is automatically removed from the WeakMap. WeakMap implementations must detect and remove such key/value pairs and any associated resources.</p> |
spec.html
Outdated
<p>An implementation may impose an arbitrarily determined latency between the time a key/value pair of a WeakMap becomes inaccessible and the time when the key/value pair is removed from the WeakMap. If this latency was observable to ECMAScript program, it would be a source of indeterminacy that could impact program execution. For that reason, an ECMAScript implementation must not provide any means to observe a key of a WeakMap that does not require the observer to present the observed key.</p> | ||
<p>WeakMap objects must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of key/value pairs in the collection. The data structure used in this WeakMap objects specification are only intended to describe the required observable semantics of WeakMap objects. It is not intended to be a viable implementation model.</p> | ||
<emu-note> | ||
<p>WeakMap and WeakSets are intended to provide mechanisms for dynamically associating state with an object in a manner that does not “leak” memory resources if, in the absence of the WeakMap or WeakSet, the object otherwise became inaccessible and subject to resource reclamation by the implementation's garbage collection mechanisms. This characteristic can be achieved by using an inverted per-object mapping of weak map instances to keys. Alternatively each weak map may internally store its key to value mappings but this approach requires coordination between the WeakMap or WeakSet implementation and the garbage collector. The following references describe mechanism that may be useful to implementations of WeakMap and WeakSets:</p> | ||
<p>WeakMap and WeakSets are intended to provide mechanisms for dynamically associating state with an object or symbol in a manner that does not “leak” memory resources if, in the absence of the WeakMap or WeakSet, the object or symbol otherwise became inaccessible and subject to resource reclamation by the implementation's garbage collection mechanisms. This characteristic can be achieved by using an inverted per-object/symbol mapping of weak map instances to keys. Alternatively, each WeakMap may internally store its key to value mappings, but this approach requires coordination between the WeakMap or WeakSet implementation and the garbage collector. The following references describe mechanism that may be useful to implementations of WeakMap and WeakSet:</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<p>WeakMap and WeakSets are intended to provide mechanisms for dynamically associating state with an object or symbol in a manner that does not “leak” memory resources if, in the absence of the WeakMap or WeakSet, the object or symbol otherwise became inaccessible and subject to resource reclamation by the implementation's garbage collection mechanisms. This characteristic can be achieved by using an inverted per-object/symbol mapping of weak map instances to keys. Alternatively, each WeakMap may internally store its key to value mappings, but this approach requires coordination between the WeakMap or WeakSet implementation and the garbage collector. The following references describe mechanism that may be useful to implementations of WeakMap and WeakSet:</p> | |
<p>WeakMap and WeakSets are intended to provide mechanisms for dynamically associating state with a value in a manner that does not “leak” memory resources if, in the absence of the WeakMap or WeakSet, the value otherwise became inaccessible and subject to resource reclamation by the implementation's garbage collection mechanisms. This characteristic can be achieved by using an inverted per-entry mapping of weak map instances to keys. Alternatively, each WeakMap may internally store its key to value mappings, but this approach requires coordination between the WeakMap or WeakSet implementation and the garbage collector. The following references describe mechanism that may be useful to implementations of WeakMap and WeakSet:</p> |
spec.html
Outdated
@@ -36656,8 +36656,8 @@ <h1>Properties of WeakMap Instances</h1> | |||
|
|||
<emu-clause id="sec-weakset-objects"> | |||
<h1>WeakSet Objects</h1> | |||
<p>WeakSet objects are collections of objects. A distinct object may only occur once as an element of a WeakSet's collection. A WeakSet may be queried to see if it contains a specific object, but no mechanism is provided for enumerating the objects it holds. If an object that is contained by a WeakSet is only reachable by following a chain of references that start within that WeakSet, then that object is inaccessible and is automatically removed from the WeakSet. WeakSet implementations must detect and remove such objects and any associated resources.</p> | |||
<p>An implementation may impose an arbitrarily determined latency between the time an object contained in a WeakSet becomes inaccessible and the time when the object is removed from the WeakSet. If this latency was observable to ECMAScript program, it would be a source of indeterminacy that could impact program execution. For that reason, an ECMAScript implementation must not provide any means to determine if a WeakSet contains a particular object that does not require the observer to present the observed object.</p> | |||
<p>WeakSet objects are collections of objects and/or symbols. A distinct object or symbol may only occur once as an element of a WeakSet's collection. A WeakSet may be queried to see if it contains a specific object or symbol, but no mechanism is provided for enumerating the objects and symbols it holds. If an object or symbol that is contained by a WeakSet is only reachable by following a chain of references that start within that WeakSet, then that value is inaccessible and is automatically removed from the WeakSet. WeakSet implementations must detect and remove such values and any associated resources.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<p>WeakSet objects are collections of objects and/or symbols. A distinct object or symbol may only occur once as an element of a WeakSet's collection. A WeakSet may be queried to see if it contains a specific object or symbol, but no mechanism is provided for enumerating the objects and symbols it holds. If an object or symbol that is contained by a WeakSet is only reachable by following a chain of references that start within that WeakSet, then that value is inaccessible and is automatically removed from the WeakSet. WeakSet implementations must detect and remove such values and any associated resources.</p> | |
<p>WeakSet objects are collections of objects and/or symbols. A distinct value may only occur once as an element of a WeakSet's collection. A WeakSet may be queried to see if it contains a specific value, but no mechanism is provided for enumerating its values. If a value that is contained by a WeakSet is only reachable by following a chain of references that start within that WeakSet, then that value is inaccessible and is automatically removed from the WeakSet. WeakSet implementations must detect and remove such values and any associated resources.</p> |
Thanks for the comments everyone. I've factored out the HasIdentity algorithm and applied @gibson042 's wording suggestions. |
spec.html
Outdated
@@ -5534,6 +5534,16 @@ <h1>IsStringPrefix ( _p_, _q_ )</h1> | |||
</emu-note> | |||
</emu-clause> | |||
|
|||
<emu-clause id="sec-hasidentity" aoid="HasIdentity"> | |||
<h1>HasIdentity ( _argument_ )</h1> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<h1>HasIdentity ( _argument_ )</h1> | |
<h1>HasUniqueIdentity ( _argument_ )</h1> |
🚲 🏠 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IsUnforgeable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"unforgeable" means something very different to me, not dealing with identity but with observable characteristics of a value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I liked @bakkot's suggestion, so I have adopted it here. Do you have a particular concern with it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I view all primitives as having identity, and the “unique identity” phrasing you used in the prose seemed more precise to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<small>isn't it still a unique identity if it's the same 3?</small>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my reading of your prose suggested that "unique" meant "can not be manifested at a distinct callsite"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I see it, the observable difference between 2
and @@iterator
, is that, for the first one you can construct (“forge”) the exact SameValue with just syntax (e.g., 2
), including built-in operations (e.g., 1 + 1
), while for the second one, you must have prior reference to some objects and/or functions in order to retrieve it (e.g., from Symbol
with Symbol.iterator
, or from Array.prototype
and Object.getOwnPropertySymbols
with Object.getOwnPropertySymbols(Array.prototype)[0]
.
That leads to “unforgeable”...
Or, equivalently, “collectable [from a WeakSet, by the GC]”, as the GC can drop the value from the WeakSet as soon as you lose any way to retrieve a reference to it. A non-symbol primitive is never collected because you can always forge a reference to it.
(Also, “unique identity” does not make sense for me: by definition, an identity is unique; or is there a double-agent hidden in the spec?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am confused by @ljharb's use of the word "identity", which is quite opposite of my understanding of how it's used usually.
"Identity" is the thing that distinguishes encapsulated things as different from one another. JS encapsulates objects and thus objects have identity: ({a:42}) !== ({a:42})
. The two objects there have the same structure, but different identities. JS does not encapsulate numbers and strings: "foo" === "foo"
, and 3 === 3
.
It is wrong to teach "identity" as the reason that 3 === 3
. 3 === 3
precisely because we don't encapsulate numbers. Python is the most infamous here, I think, in that it doesn't encapsulates number up to 256 due to implementation reasons.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would be happy with @claudepache's suggestions of "collectable" or "unforgeable" to describe predicate, as well as "has identity". I think we can defer settling on a conclusion here until we're getting ready to merge this PR.
spec.html
Outdated
<p>An implementation may impose an arbitrarily determined latency between the time a key/value pair of a WeakMap becomes inaccessible and the time when the key/value pair is removed from the WeakMap. If this latency was observable to ECMAScript program, it would be a source of indeterminacy that could impact program execution. For that reason, an ECMAScript implementation must not provide any means to observe a key of a WeakMap that does not require the observer to present the observed key.</p> | ||
<p>WeakMap objects must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of key/value pairs in the collection. The data structure used in this WeakMap objects specification are only intended to describe the required observable semantics of WeakMap objects. It is not intended to be a viable implementation model.</p> | ||
<emu-note> | ||
<p>WeakMap and WeakSets are intended to provide mechanisms for dynamically associating state with an object in a manner that does not “leak” memory resources if, in the absence of the WeakMap or WeakSet, the object otherwise became inaccessible and subject to resource reclamation by the implementation's garbage collection mechanisms. This characteristic can be achieved by using an inverted per-object mapping of weak map instances to keys. Alternatively each weak map may internally store its key to value mappings but this approach requires coordination between the WeakMap or WeakSet implementation and the garbage collector. The following references describe mechanism that may be useful to implementations of WeakMap and WeakSets:</p> | ||
<p>WeakMap and WeakSets are intended to provide mechanisms for dynamically associating state with an object or symbol in a manner that does not “leak” memory resources if, in the absence of the WeakMap or WeakSet, the object or symbol otherwise became inaccessible and subject to resource reclamation by the implementation's garbage collection mechanisms. This characteristic can be achieved by using an inverted per-object/symbol mapping of weak map instances to keys. Alternatively, each WeakMap may internally store its key to value mappings, but this approach requires coordination between the WeakMap or WeakSet implementation and the garbage collector. The following references describe mechanism that may be useful to implementations of WeakMap and WeakSet:</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is trailing whitespace on this line.
https://travis-ci.org/github/tc39/ecma262/jobs/696618002#L226-L233
Specification PR for https://github.com/tc39/proposal-symbols-as-weakmap-keys Note that both registered and unregistered Symbols are permitted here. Closes tc39#1194
e5ee707
to
4d0b82c
Compare
I'm writing some changes on top of this PR but it's being hard to properly sync the branches with this current one. Here is a preview: |
3d0c24c
to
7a79833
Compare
Update to @leobalter's link: main...leobalter:symbol-as-weakmap-key |
Closed by #2777? |
Indeed; replaced by #2777. |
Specification PR for https://github.com/tc39/proposal-symbols-as-weakmap-keys
Note that both registered and unregistered Symbols are permitted here.
Not intended to land until this proposal reaches Stage 4 (currently: Stage 1).
Note, the intention would be to permit Symbols in WeakRefs and registered in FinalizationRegistry as well. This includes creating a definition of liveness for Symbols, which is expected to generally match that of objects. This logic will be added to the PR once WeakRefs reach Stage 4 (which is hoped to happen before this proposal reaches Stage 3).
(I'm not sure if this PR is missing something; it ended up being very straightforward.)
Closes #1194
Visual diff (thanks @arai-a!) https://arai-a.github.io/ecma262-compare/?pr=2038