Giter Club home page Giter Club logo

proposal-symbols-as-weakmap-keys's People

Contributors

acutmore avatar leobalter avatar littledan avatar psychollama avatar rickbutton avatar rricard avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

proposal-symbols-as-weakmap-keys's Issues

Shims of well-known symbols

In the SES call today we discussed how a shim of a well-known symbol would have to be implemented to be transparent with ShadowRealm.

There are basically 2 approaches, each with their caveats:

  • The shim uses a unique symbol and adds it to the realm's global Symbol. However to ensure that the identity of that symbol is consistent across realms, shims loaded in multiple realms have to coordinate somehow. One way would be to wrap the ShadowRealm constructor.
  • The shim uses a registered symbol. It similarly adds it to the realm's global Symbol, but because it uses a registered symbol, no coordination is necessary. However if well-known symbols are allowed as WeakMap key, then the shim needs to wrap WeakMap, and store entries keyed by this fake well-known symbol into a side Map.

Both shims approaches have fidelity issues. In hindsight, I wish well-known symbols were all registered. However if well-known symbols were disallowed as WeakMap keys, it'd allow greater shim fidelity without increased complexity. They could use registered symbols as the synchronization mechanism across realms, with only Symbol.keyFor remaining as fidelity discrepancy for shimmed well-known symbols.

Alternative solution: Identity Symbols

As #21 discussion, symbol as weakmap key have some arguments on registered symbols, both sides seems have good reasons, maybe we should find some tradeoffs which could satisfy both. I think the root cause of the issues is "symbol as weakmap keys" is too general, as I understand, the main use case is sharable identity, which do not need to be such general. Instead, we could introduce a much limited API:

  • Symbol.of(object) create the identity symbol for the object
  • get Symbol.prototype.object return the object of the identity symbol (return undefined for non-identity symbols)

Usage:

const obj = {}
const sym = Symbol.of(obj)
assert(symbol.object === obj)

Identity symbols (special symbol which ref to the object) would be somewhat like registered symbols (special symbol which ref to the string), so I expect it won't have much troubles to implement.

Note, such API is similar to Object.createSharableIdentity() idea except it use symbol for identity instead of frozen empty object.

Use of registered symbols would allow observation that a `WeakMap` entry has been freed

I've just had a discussion with WH to get a clear picture of his objection to allowing symbols created with Symbol.for() as WeakMap keys.

To summarize, This is the use-case that must be disallowed.

  1. Symbol.for('name') gets used as a WeakMap key.
  2. Later, no references to Symbol.for('name') exist other than the WeakMap key and the (virtual) GlobalSymbolRegistry entry, which don't count. So, both of these are effectively freed.
  3. Still later Symbol.for('name') is called again and the result used to attempt lookup in the same WeakMap, finding nothing.

The key misunderstanding many of us have had revolves around the assumption that the GlobalSymbolRegistry entry defined in the spec must keep the Symbol.for() keys alive forever, making them effectively the same as well-known symbols that are stored on global objects. This is incorrect.

In our conversation WH explained it like this.

The VM table you're referring to is spec convenience fiction and an implementation need not implement it that way.

There are many such spec fictions. Consider a program that sits in a tight loop creating objects and not storing them anywhere. Before we had weak maps, we had no notion of object destruction, so per the spec you'd quickly exhaust memory with objects. But a realistic implementation doesn't need to do it that way and can run such a loop indefinitely. Similarly, the VM table is a spec fiction that ensures that when you call Symbol.for twice with the same string, you get the same symbol. Now imagine a program sitting in a tight loop creating consecutive unique strings "0000000000", "0000000001", "0000000002", etc., calling Symbol.for on them, but not storing the symbols anywhere. To preserve the user-visible Symbol.for semantics, an implementation need only to keep track of live symbols, so it's possible for an implementation to run such a loop indefinitely without exhausting memory. That table of all Symbol.for symbols is spec fiction.

So, I believe this proposal & its spec text need to be updated to disallow use of registered symbols as WeakMap keys.

Helpful predicate functions

I'm spinning an issue off from @rricard 's comment here: #23 (review)

I remember starting to discuss the different variants of helper functions that could land with this proposal, but I don't recall if we came to a clear answer or not as I failed to take detailed notes.

cc: @ljharb @syg @codehag


Some options for helpers:

A) WeakMap.isValidKey et al

There would also be WeakSet.isValidValid, WeakRef.isValidTarget and FinalizationRegistry.isValidTarget, which would likely all share the same function instance if the logic is the same. This predicate returning true/false would be a direct indication of if the same value would-not/would throw if attempted to be used with an instance of the class.

One issue that has been raised with this helper is that it is likely to 'lock' in the set of valid values; if the only time the logic for this function can change is to encompass new types when they are added to the language, and couldn't change (across versions) for existing types. For example: relaxing the rule to allow 'well-known' symbols in the future. This could impact Record&Tuple, if the initial MVP spec for them says they are not valid WeakMap keys, then this could mean they can never be, as the predicate would need to change its result.

B) Object.isUnforgeable

(Doesn't necessarily need to be on Object). The key idea here, as I understand it, is to de-couple the predicate from if the value can be used in a weak collection. i.e. it can be used as an indicator but does not necessarily perfectly divide values into the two sets of valid/invalid WeakMap keys.

This could potentially allow the set of valid WeakMap keys to change as this predicate itself would always give the same result for a given input across versions. For example isUnforgeable(Symbol.iterator) may always return false**, but registered symbols may throw when used as WeakMap keys in one version but then relaxed in future versions. Or for Record&Tuple, isUnforgeable(Tuple(Symbol)) could always return true, but maybe this does not guarantee that it is also a valid WeakMap key, relaxing this could then be a future separate proposal.

**

isUnforgeable(Symbol.iterator) === false may be wrong, it would depend on how we interpret forgeability.

// index.js
delete Array.prototype[Symbol.unscopables];
delete Symbol.prototype.constructor;
delete globalThis.Symbol;
// is `@@unscopables` now unreachable? maybe not as [HasBinding](https://tc39.es/ecma262/multipage/executable-code-and-execution-contexts.html#sec-object-environment-records-hasbinding-n) still references it 
const unscopables = new ShadowRealm().evaluate(`Symbol.unscopables`); // have I re-forged it?

?) Other options?

Z) No new predicate functions

One option is to not introduce new predicates in the spec itself. This would leave userland to create their own predicates and/or use try/catch.

clarification on "not needed anymore" and garbage collection

The README is really clear!

Re:

Boxes will not keep objects indefinitely in memory. When a box is not needed anymore, the attached object can be let go.

Does "a box is not needed anymore" mean the same thing as "a box is inaccessible"?

Is this sentence saying the same thing as "when the box is garbage-collected, the attached object can be garbage-collected as well"?

If so, we might want to tweak the semantics so that the boxed object is eligible for collection when the object and its box are inaccessible.

const obj = { hello: "world" };
const box = Box(obj);
window.leakObj = obj; // the box can be collected, but the object itself must live on

FYI: Repo updates

I added a spec draft in the main branch. I preserved the original text in the preserved branch, see the diff here.

Describe relationship to the Record and Tuple proposal

This proposal may complement Records and Tuples. However, it's just not a prerequisite: the things you can do in userland are "good enough" to accomplish a lot of things with Records and Tuples, and let the feature "pay for itself". Therefore, while it's good to discuss broader mechanisms for boxing objects, it shouldn't block the Records and Tuples proposal. It's important to explain this relationship in the README.

Realms use case

As seen in the recent discussions for Realms, this proposal has now become a very useful feature that could be used to share identities through multiple realms. Using Weakmaps with symbol keys would be a first step to config membranes.

This proposed feature goes straight to our usage without increased complexity. Transferring a symbol identity through realms seems like a separate concern. Although, using Records and Tuples for this separate concern still feels overkill as we would need to specify what it means to transfer their structure to set identity references. There is no depreciation for the use cases of R&T, but we'd need to enable Symbols as WeakMap keys as the base for the next proposal-step.

Describe how RefCollection relates to the other two ideas

There's no big fundamental difference between RefCollection, Box and Symbols-as-WeakMap-keys in my mind: they're all about making it so that a primitive type's "identity" can be used to "point" to an object. In the final section of the README, it'd be good to explain this. Maybe reviewers will suggest working somewhere else on the continuum.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.