Will any new features be tied to constructors?

# Anne van Kesteren (4 years ago)

For custom elements in DOM there's a proposal to have the constructor be controlled by the user agent and have some kind of callback that actually initiates the element. This has some advantage in that it allows the script to load lazily while the parser continues running.

However, if the user agent always invokes the constructor, would that exclude us from new features? E.g. I could imagine private data properties to be an allocation affair of sorts.

(Note: I'm not personally pushing this design, I'm just exploring the consequences.)

# Anne van Kesteren (4 years ago)

On Sat, Jun 27, 2015 at 2:21 AM, Anne van Kesteren <annevk at annevk.nl> wrote:

For custom elements in DOM there's a proposal to have the constructor be controlled by the user agent and have some kind of callback that actually initiates the element. This has some advantage in that it allows the script to load lazily while the parser continues running.

However, if the user agent always invokes the constructor, would that exclude us from new features? E.g. I could imagine private data properties to be an allocation affair of sorts.

(Note: I'm not personally pushing this design, I'm just exploring the consequences.)

To clarify, since this was not completely clear, the question is whether anything other than object allocation will be allowed only through a constructor? That is, do any JavaScript language designers have plans to restrict certain object functionality to constructors, or will constructors only ever be responsible for object allocation and nothing else?

The answer to this question would greatly impact the way we make DOM extensible. And given that we plan to decide on that in three weeks time any quick answer would be appreciated.

# Allen Wirfs-Brock (4 years ago)

On Jun 29, 2015, at 11:29 AM, Anne van Kesteren wrote:

On Sat, Jun 27, 2015 at 2:21 AM, Anne van Kesteren <annevk at annevk.nl> wrote:

For custom elements in DOM there's a proposal to have the constructor be controlled by the user agent and have some kind of callback that actually initiates the element. This has some advantage in that it allows the script to load lazily while the parser continues running.

However, if the user agent always invokes the constructor, would that exclude us from new features? E.g. I could imagine private data properties to be an allocation affair of sorts.

(Note: I'm not personally pushing this design, I'm just exploring the consequences.)

To clarify, since this was not completely clear, the question is whether anything other than object allocation will be allowed only through a constructor? That is, do any JavaScript language designers have plans to restrict certain object functionality to constructors, or will constructors only ever be responsible for object allocation and nothing else?

The answer to this question would greatly impact the way we make DOM extensible. And given that we plan to decide on that in three weeks time any quick answer would be appreciated. Thanks!

TC39 hasn't yet agreed upon a design for adding "private state" to user defined ES6 objects, but at least one plausible design would model such state very similarly to how "internal slots" are handled in ES6, including that the final internal state "shape" of an object must be determined by the time it is allocated. In this regard, it seems that a custom element might frequently want to make use of such private state if it was available.

How would your hypothetical early allocated objects be observably exposed? If ES code has access to an object in such a state, what could the code reasonably expect to do with it? For example, if the script that defines the specific custom element class has not been loaded then the neither the [[Prototype]] or any of the prototype properties of the custom element instance would be known or available.

In the general case, what you are asking for seems to be roughly equivalent to a "becomes" operation. Are you essentially trying to obtain early access to the identity of the custom element? If no operations (other than ===) are allowed prior to final allocation, then I can imagine some sort of more specialized deferred allocation that would give you early identity access without the full compleity of "becomes".

But is it even necessary to preserve identity? After all, scripts can dynamically add and remove DOM elements at any time. So it seems that there really isn't any guarantee that the identity of DOM elements aren't dynamically changing.

What's wrong with inserting a "deferred custom element" node into the DOM when you initially parse and then replacing it with an actual custom element instance of the correct class when when the script it depends upon has been loaded?

# Anne van Kesteren (4 years ago)

On Tue, Jun 30, 2015 at 5:54 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

How would your hypothetical early allocated objects be observably exposed?

The design is basically that the browser first creates a "normal" element, and at a later point changes the prototype and invokes the callback. It's explained in some detail in this email:

lists.w3.org/Archives/Public/public-webapps/2015JanMar/0230.html

What's wrong with inserting a "deferred custom element" node into the DOM when you initially parse and then replacing it with an actual custom element instance of the correct class when when the script it depends upon has been loaded?

There's some rationale on this page:

lists.w3.org/Archives/Public/public-webapps/2015JanMar/0230.html

In brief, you might lose added event listeners, gets complicated with attributes and children, mutation observers will be somewhat spammy. Domenic and Dimitry might be able to elaborate more.

# Kevin Smith (4 years ago)

The design is basically that the browser first creates a "normal" element, and at a later point changes the prototype and invokes the callback.

Changes the prototype dynamically? We're generally moving away from such shenanigans.

That would indeed interact poorly with some of the designs for private state that we've been entertaining. In such a scheme private state "slots" are allocated when the object is created. But in your use case you wouldn't know what slots to allocate until after you've created the object. And then it's too late.

# C. Scott Ananian (4 years ago)

But the design might work well as a proxy object? It could delegate to the "real" object, with its private slots, after that object is created.

# Anne van Kesteren (4 years ago)

On Tue, Jun 30, 2015 at 6:41 PM, Kevin Smith <zenparsing at gmail.com> wrote:

Changes the prototype dynamically? We're generally moving away from such shenanigans.

That would indeed interact poorly with some of the designs for private state that we've been entertaining. In such a scheme private state "slots" are allocated when the object is created. But in your use case you wouldn't know what slots to allocate until after you've created the object. And then it's too late.

Right, my personal preference is to just use constructors. That however has two drawbacks:

  1. Leaves upgrading nodes up to the developer. Or requires them to load script synchronously, blocking the parser. Neither is particularly great.
  2. Would allow JavaScript to run while cloning nodes (needed for various editing operations and printing in some browsers) would be a pain as the C++ algorithms are not prepared for it. Very much unclear if that's feasible within any reasonable amount of time.
# Domenic Denicola (4 years ago)

Allen, Kevin: I think the key question about private state and how it interacts with Anne's question is this.

Given a base class looking roughly like

class HTMLElement extends Element {
  constructor(...) {
    super(...);
    // ...other stuff...
    this[Element.init]();
  }
}

then, will the following work?

class CustomElement extends HTMLElement {
  [Element.init]() {
    // initialize private state
  }
}

Or would an actual constructor be required?

class CustomElement extends HTMLElement {
  constructor(...args) {
    super(...args);
    // initialize private state
  }
}

Stated another way, which might be a bit stronger: will it be lexically required that private state initialization be within the constructor, or will it only be temporally required?

That question is, I think, what Anne is essentially asking when he asks about features that are "tied to constructors".

# Domenic Denicola (4 years ago)

From: es-discuss [mailto:es-discuss-bounces at mozilla.org] On Behalf Of C. Scott Ananian

But the design might work well as a proxy object? It could delegate to the "real" object, with its private slots, after that object is created.

We briefly discussed this with the V8 team. Their opinion was that making fast proxies was a problem at least as hard as making proto-swizzling work seamlessly. Not to mention all the additional complexities introduced by private state and proxies, which there are a few centithreads in the archives about.

# Allen Wirfs-Brock (4 years ago)

On Jun 30, 2015, at 5:54 PM, Domenic Denicola wrote:

Allen, Kevin: I think the key question about private state and how it interacts with Anne's question is this.

Given a base class looking roughly like

class HTMLElement extends Element {
 constructor(...) {
   super(...);
   // ...other stuff...
   this[Element.init]();
 }
}

then, will the following work?

no, not in the way that I believe you intend

class CustomElement extends HTMLElement {
 [Element.init]() {
   // initialize private state
 }
}

Or would an actual constructor be required?

yes

class CustomElement extends HTMLElement {
 constructor(...args) {
   super(...args);
   // initialize private state
 }
}

Stated another way, which might be a bit stronger: will it be lexically required that private state initialization be within the constructor, or will it only be temporally required?

It isn't that subclass specific private state "initialization" must be performed in the constructors. In the design that Kevin and I have been working on, the total number of private state slots (and some meta data for each one) must be knowable and fixed when an object is allocated (in other words, private slots cannot be added to an object after it is initially allocated). Those slots can be "initialized" in an application manner at any time and in any manner.

# Domenic Denicola (4 years ago)

From: Allen Wirfs-Brock [mailto:allen at wirfs-brock.com]

no, not in the way that I believe you intend

Can you explain why? Is the design you and Kevin have been working on based on lexical restrictions?

It isn't that subclass specific private state "initialization" must be performed in the constructors. In the design that Kevin and I have been working on, the total number of private state slots (and some meta data for each one) must be knowable and fixed when an object is allocated (in other words, private slots cannot be added to an object after it is initially allocated).

This seems like it then compares poorly with weak maps for private state. It makes sense as a strong mode restriction, but not as a default one...

Anyway, the design for upgradable custom elements is based around the idea that subclasses would never need to customize the allocator, thus allowing the UA to do their magical allocation of C++ HTMLElement stuff. If private state requires customizing the allocator, I am not sure that custom elements would be able to take advantage of it anyway... I suppose it depends on the details of the proposal.

# Anne van Kesteren (4 years ago)

On Wed, Jul 1, 2015 at 2:54 AM, Domenic Denicola <d at domenic.me> wrote:

Stated another way, which might be a bit stronger: will it be lexically required that private state initialization be within the constructor, or will it only be temporally required?

I don't see how this matters given that Dmitry's design depends on not executing JavaScript while constructing the element. Whereas if you put thisElement.init in the constructor it totally would.

# Domenic Denicola (4 years ago)

From: Anne van Kesteren [mailto:annevk at annevk.nl]

I don't see how this matters given that Dmitry's design depends on not executing JavaScript while constructing the element. Whereas if you put thisElement.init in the constructor it totally would.

Dmitry's design does not depend on that. In fact Dmitry's design includes thisElement.init in the constructor. See lists.w3.org/Archives/Public/public-webapps/2015JanMar/0230.html

The essence of Dmitry's design is to disallow custom allocation, while allowing custom initialization. This allows you to optionally decouple the two stages when necessary (upgrades, cloning, etc.) while also getting the goodness where author code doing new MyElement(...) calls both built-in allocation and custom initialization immediately.

# Anne van Kesteren (4 years ago)

On Wed, Jul 1, 2015 at 10:56 AM, Domenic Denicola <d at domenic.me> wrote:

Dmitry's design does not depend on that. In fact Dmitry's design includes thisElement.init in the constructor.

Fair, but it does depend on that not always being invoked at the same time as the constructor. So even if not being lexically part of the constructor was fine, you could still not depend on it being invoked at the same time.

# Domenic Denicola (4 years ago)

From: Anne van Kesteren [mailto:annevk at annevk.nl]

Fair, but it does depend on that not always being invoked at the same time as the constructor. So even if not being lexically part of the constructor was fine, you could still not depend on it being invoked at the same time.

Yeah, you're right. But only because this private state feature is for some reason tied to object allocation. So going back to your original question,

To clarify, since this was not completely clear, the question is whether anything other than object allocation will be allowed only through a constructor?

I guess the answer is still no :).

The question is whether this private state feature design (1) really needs to be tied to allocation; (2) if it does, then will it even be usable for custom elements?

I.e., do you see any plausible world in which you're allowed to create a custom element with a custom allocator, instead of the browser-supplied HTMLElement one?

# Kevin Smith (4 years ago)

The essence of Dmitry's design is to disallow custom allocation, while allowing custom initialization. This allows you to optionally decouple the two stages when necessary (upgrades, cloning, etc.) while also getting the goodness where author code doing new MyElement(...) calls both built-in allocation and custom initialization immediately.

If we go with a private state design where the internal slots are not dynamic, but fixed at birth (which is where we'd like to go), then a "becomes-like" solution for custom elements wouldn't be compatible with it. It would mean that custom elements wouldn't be able to have usable private slots.

# Anne van Kesteren (4 years ago)

On Wed, Jul 1, 2015 at 2:50 PM, Domenic Denicola <d at domenic.me> wrote:

I.e., do you see any plausible world in which you're allowed to create a custom element with a custom allocator, instead of the browser-supplied HTMLElement one?

I'm not sure I follow. In a world where custom elements are normal subclassed objects, they would just call super() from the constructor to set the browser-supplied bits and then add whatever else is needed themselves. Or are you saying that super() would fully allocate the object and prevent adding new private state (or other features tied to constructors)?

# Domenic Denicola (4 years ago)

From: Anne van Kesteren [mailto:annevk at annevk.nl]

In a world where custom elements are normal subclassed objects, they would just call super() from the constructor to set the browser-supplied bits and then add whatever else is needed themselves.

Yes, that is the Dmitry proposal.

Or are you saying that super() would fully allocate the object

Yes, that is how ES2015 works.

and prevent adding new private state

Apparently Kevin and Allen's private state proposal is based on private state being installed at allocation time, so yes, since super() fully allocates the object, this would prevent private state for custom elements.

Personally I think this is a definite negative for any such private state proposal, since it makes it significantly less expressive than weak maps. But I suppose when the proposal is proposed, we will have that discussion.

(or other features tied to constructors)?

Well, it depends on if those features are tied to allocation (like this private state proposal) or to initialization.

# Anne van Kesteren (4 years ago)

On Wed, Jul 1, 2015 at 3:49 PM, Domenic Denicola <d at domenic.me> wrote:

From: Anne van Kesteren [mailto:annevk at annevk.nl]

In a world where custom elements are normal subclassed objects, they would just call super() from the constructor to set the browser-supplied bits and then add whatever else is needed themselves.

Yes, that is the Dmitry proposal.

This is confusing. The Element.create callback from Dmitry can also be called post-construction, so it's strictly different from most subclassing scenarios.

Apparently Kevin and Allen's private state proposal is based on private state being installed at allocation time, so yes, since super() fully allocates the object, this would prevent private state for custom elements.

So are you saying that would make private state harder to use for any kind of subclassing scenario?

# Allen Wirfs-Brock (4 years ago)

On Jun 30, 2015, at 5:57 PM, Domenic Denicola wrote:

From: es-discuss [mailto:es-discuss-bounces at mozilla.org] On Behalf Of C. Scott Ananian

But the design might work well as a proxy object? It could delegate to the "real" object, with its private slots, after that object is created.

We briefly discussed this with the V8 team. Their opinion was that making fast proxies was a problem at least as hard as making proto-swizzling work seamlessly. Not to mention all the additional complexities introduced by private state and proxies, which there are a few centithreads in the archives about.

This could not be a normal proxy because the target object needs to be available when the proxy object needs to be created. Given that, I suspect that a special proxy could be introduced that dealt with those issues.

But. I'm not necessarily advocating that solution.

Do one has yet explained to me, what is wrong with simply initially inserting a dummy (generic) custom element node during DOM parsing and latter (after the required JS code has loaded) replacing that node with a new more specific node that is an instance of the named subclass.

My premise is that once script is running DOM nodes can be arbitrarily added/removed/modified as a side-effect of any script function. Hence there is no guarantees that any two script navigations to some particular node location in the DOM will yield the same (===) object and scripts generally should not be making any such identity assumptions. If there are no identify assumptions, then you can safely replace such dummy custom element nodes with the actual node when it becomes available. (probably between microtasks, would be best)

# Domenic Denicola (4 years ago)

From: Allen Wirfs-Brock [mailto:allen at wirfs-brock.com]

Do one has yet explained to me, what is wrong with simply initially inserting a dummy (generic) custom element node during DOM parsing and latter (after the required JS code has loaded) replacing that node with a new more specific node that is an instance of the named subclass.

Anne explained this to you in esdiscuss.org/topic/will-any-new-features-be-tied-to-constructors#content-3. There's also the issue that replacing nodes that have children gets much more complicated, especially if those nodes are high up in the tree. More detail at w3c/webcomponents/blob/gh-pages/proposals/Why-Upgrades.md.

My premise is that once script is running DOM nodes can be arbitrarily added/removed/modified as a side-effect of any script function.

In practice, this is not how one programs against the DOM. One assumes that things generally don't change except for good reason (i.e. author-initiated reason). It's common practice to save document.querySelector('#my-thingy') to a variable, and operate on it for many event loop turns, until some known event occurs. (Like Ajax fake page navigation, or blowing away the parent component, or closing a dialog, similar.)

It's decidedly bad practice to re-query the DOM for an element every time you want to use it, which seems to be what you're advocating as necessary.

# Allen Wirfs-Brock (4 years ago)

On Jun 30, 2015, at 8:31 PM, Domenic Denicola wrote:

From: Allen Wirfs-Brock [mailto:allen at wirfs-brock.com]

no, not in the way that I believe you intend

Can you explain why? Is the design you and Kevin have been working on based on lexical restrictions?

No sure what you specifically mean. It requires that private slots be declared as part of a class definitions so that the metadata need to allocate them is available to the class constructor.

It isn't that subclass specific private state "initialization" must be performed in the constructors. In the design that Kevin and I have been working on, the total number of private state slots (and some meta data for each one) must be knowable and fixed when an object is allocated (in other words, private slots cannot be added to an object after it is initially allocated).

This seems like it then compares poorly with weak maps for private state. It makes sense as a strong mode restriction, but not as a default one...

It is the "conventional model" of private state that is used by most languages. It has lots of very desirable characteristics. And, it's hard enough to insert one private state model into ES. We aren't going to end up with more than one, at the language level.

Anyway, the design for upgradable custom elements is based around the idea that subclasses would never need to customize the allocator, thus allowing the UA to do their magical allocation of C++ HTMLElement stuff. If private state requires customizing the allocator, I am not sure that custom elements would be able to take advantage of it anyway... I suppose it depends on the details of the proposal.

This is model is, to a first approximation the C++ model and the also the model the ES currently uses for built-ins so I don't expect that UA allocators will have significant difficulties supporting it.

# Domenic Denicola (4 years ago)

From: Allen Wirfs-Brock [mailto:allen at wirfs-brock.com]

This is model is, to a first approximation the C++ model and the also the model the ES currently uses for built-ins so I don't expect that UA allocators will have significant difficulties supporting it.

Really?

Right now the UA allocators for all elements contains a single private slot, a pointer to the backing C++ object. Then a whole parallel hierarchy, of the C++ object tree mapping to multiple corresponding JS object trees, follows from this. Private state is, of course, stored in the backing C++ object. Maybe some implementers can correct, but I doubt retrofitting this structure to support additional arbitrary author-defined private slots, introduced at any level in the hierarchy, is at all insignificant.

Similarly, for several V8 built-ins, private state is not done via the allocator at all, but instead via "private symbols" that act quite similar to data properties. They can be added or removed at any time. In short, they're much more part of initialization than of allocation.

I don't think there's anything like the model the ES spec uses in play in implementations. I would anticipate significant difficulties.

It has lots of very desirable characteristics.

Forgive me if I am speaking in ignorance. But from what has been presented so far, it seems to have one strongly undesirable characteristic, which is that it is no longer possible to decompose a non-custom-allocator constructor into base-class allocator and subclass initialization. That is, previously it was easy to "emulate" the constructor for

class Derived extends Base {
  constructor(...args) {
    super(a, b, c);
    doInitCode(this, ...args);
  }
}

via a function

function makeDerived(...args) {
  const o = Reflect.construct(Base, [a, b, c], Derived);
  doInitCode(o, ...args);
  return o;
}

This allows you to recover the allocation/initialization split that was lost when moving away from @@create, while still preserving the instantiation reform benefits in the general case.

It sounds like this kind of emulation is not possible with your private state proposal. Whereas, of course, it is possible with weak maps (which exist today) or "private symbols" (what V8 uses today internally).

# Kevin Smith (4 years ago)

The fact that you're dynamically changing the prototype as a part of this solution is a strong indicator that this usage of subclassing is somewhat questionable. I suspect that you'll find other gotachas with this approach.

I understand that the DOM is dealing with some design constraints that are less than ideal, but the only "right" ways to do this that I can think of at the moment are:

  • Swap out the element when the custom class is registered, as Allen suggested.
  • Use composition instead of subclassing to define custom behavior.
# Kevin Smith (4 years ago)
class Derived extends Base {
  constructor(...args) {
    super(a, b, c);
    doInitCode(this, ...args);
  }
}

via a function

function makeDerived(...args) {
  const o = Reflect.construct(Base, [a, b, c], Derived);
  doInitCode(o, ...args);
  return o;
}

That's still theoretically possible, because new.target (Derived in this case) carries with in the list of slots that must be allocated. Once we "super up" to the root constructor, the allocator gets that list from new.target.

But as I understand it, the difficulty for HTML element subsclassing is that you don't event know what "Derived" might be until sometime later.

# Boris Zbarsky (4 years ago)

On 7/1/15 11:12 AM, Domenic Denicola wrote:

Right now the UA allocators for all elements contains a single private slot, a pointer to the backing C++ object.

Just as a note, this is true conceptually in the specifications but happens to not be true as a matter of implementation reality in either Gecko or (planned? not sure where they are with their fused allocation setup) Servo. There can be various numbers of preallocated private slots in practice.

The UA allocators for elements contain some UA-determined set of private slots would be a better way of putting it.

Private state is, of course, stored in the backing C++ object.

This is, again, not true for Gecko. Some private state is stored in the backing C++ object. Some (e.g. the backing Map for an IDL maplike) is stored directly in a private slot of the JS object. This is a matter of implementation convenience, of course; no spec defines where these things should be stored; it just happened to be easier to do the GC bits this way.

Maybe some implementers can correct, but I doubt retrofitting this structure to support additional arbitrary author-defined private slots, introduced at any level in the hierarchy, is at all insignificant.

I can't speak to the difficulties of doing or not doing this in SpiderMonkey without us having implemented this. However, I suspect that whatever setup normal Object ends up using here in SpiderMonkey would also be usable by DOM objects...

I obviously can't speak for other implementations.

# Domenic Denicola (4 years ago)

Thanks for the corrections Boris. I was basing what I said on a half-remembered version of ask.mozilla.org/question/850/how-do-webidl-methodsgetterssetters-tell-whether-objects-are-of-the-right-types, but upon re-reading that I see that I missed the "at least" in "at least one reserved slot", and made a few other unwarranted assumptions along the way.

My apologies to Allen and everyone else for misleading assertions.

# Boris Zbarsky (4 years ago)

On 7/1/15 11:39 PM, Domenic Denicola wrote:

but upon re-reading that I see that I missed the "at least" in "at least one reserved slot"

Yeah, it's hiding in there pretty well. ;)

I actually do have a related question, though. In the private state proposals we're talking about, how would it be observable whether the private slots the class defines are in fact allocated as part of the object's allocation or separately?

# Kevin Smith (4 years ago)

I actually do have a related question, though. In the private state proposals we're talking about, how would it be observable whether the private slots the class defines are in fact allocated as part of the object's allocation or separately?

Not sure I understand the question. If the internal shape is fixed from birth (allocation-time), there is no way to allocate private slots separately.

Are you suggesting that the DOM could define some magic way to dynamically allocate private slots and supposedly hide that fact from the user?

Only if you consider object identity and "===" as meaningless : )

let el = document.createElement("foo-bar"); let Custom = class extends HTMLElement { private @x; initElement() { this. at x = 1; } getX() { return this. at x; } }; try { Custom.prototype.getX.call(el); // throws a TypeError: no @x } catch (x) {} document.registerElement("foo-bar", Custom); Custom.prototype.getX.call(el); // No type error, returns 1

# Boris Zbarsky (4 years ago)

On 7/2/15 12:18 AM, Kevin Smith wrote:

I actually do have a related question, though.  In the private state
proposals we're talking about, how would it be observable whether the
private slots the class defines are in fact allocated as part of the
object's allocation or separately?

Not sure I understand the question. If the internal shape is fixed from birth (allocation-time), there is no way to allocate private slots separately.

Ah, I see. So what's observable is not whether things are a contiguous chunk of memory or whatnot but rather whether the slots exist. And a proposed invariant is that the slots, once observed to exist or not cannot change that state. Is my understanding correct now?

Are you suggesting that the DOM could define some magic way to dynamically allocate private slots and supposedly hide that fact from the user?

Not suggesting anything yet; just trying to understand the constraints we have here.

As a matter of implementation, it would probably be possible to implement private slots in the spec sense in a way that can be dynamically added to existing objects. But that's not the externally visible behavior being proposed for private slots, which makes sense.

# Kevin Smith (4 years ago)

Ah, I see. So what's observable is not whether things are a contiguous chunk of memory or whatnot but rather whether the slots exist. And a proposed invariant is that the slots, once observed to exist or not cannot change that state. Is my understanding correct now?

Yes.

# Andreas Rossberg (4 years ago)

On 1 July 2015 at 17:12, Domenic Denicola <d at domenic.me> wrote:

Similarly, for several V8 built-ins, private state is not done via the allocator at all, but instead via "private symbols" that act quite similar to data properties. They can be added or removed at any time. In short, they're much more part of initialization than of allocation.

For the record, the ability to do this is rather an incidental consequence of private symbols. We don't remove private state anywhere, nor did I intend it to be used that way. There is one case where we add a private field dynamically (attaching a stack trace to a thrown object), but that is a half-broken hack anyway.

I'd love to have a proper allocation-time notion of private state, like Allen & Kevin suggest. You still have weak maps for more dynamic relations.

# Mark Miller (4 years ago)

For the record, there are no so-called private symbols. The concept being referred to here is an implementation-only concept for naming an internal property. These naming-things are never reified and available to JS code and must not be.