Attendees:
- Bradley Farias (BFS)
- Jordan Harband (JHD)
- Shu-yu Guo (SYG)
- Hax (JHX)
- Jack Works (JWK)
- Richard Gibson (RGN)
SYG: Let's clear up Hax's concern about ergonomic checks for private fields.
JHD: It's not clear to the rest of us what exactly Hax's concerns are despite explanations. One concern is about the # syntax, which I believe has been cleared up in committee. Another concern is the symmetry of #, if you can do #foo in x, then you should be able to do x[#foo].
JHX: I've written up an issue on the GH, #12, about my thoughts. I don't think the proposal is a good solution for the requirements. #13 discusses other solutions for the problem space.
JHD: Let me speak to #13 for a minute. I don't think that's a replacement for this proposal. As I've explained in this issue, we can install private fields onto arbitrary objects. This proposal can target specific fields. I think it's cleaner to reference a specific field than to reference a class. I think both of these things can coexist. The existence of the ergonomic field brand checking feature does not preclude or conflict with the future proposal. I don't think there's any value in delaying this proposal for the future proposal. In all the examples discussed in #13, they don't discuss private fields at all, which means they don't have semantic overlap with private fields. #13 is about "is this value a thing", which is a different kind of check? I've left #13 open so far, but I don't think that has any impact on what we do with the current proposal.
JHX: I think there's a problem here. If we have some general test on the shape, not on the single field, it seems it already solves the private field check problem. It only leaves the friend usage.
JHD: From a clarity POV, it might be functionally equivalent but it is not redundant. I think it is far far superior to check the field's existence before accessing that field than to check if a thing is a class Foo, then because it is a class foo that it has all the implicit behavior.
JHX: It feels like if we check a field, it's very like we check a property. And this usage is more like duck-type usage. I really feel if we use class and private fields, it's on the other side. You want to check if it's a real instance of a class just like other programming language.
BFS: What do you mean by "real instance of class"?
JHX: We can use some real use case. Typical use case is equals: if we want to implement equals, if the other object isn't a real instance we just throw TypeError.
BFS: But what does real instance of class mean?
JHX: That it's an instance created by the constructor of the class.
BFS: It sounds like you want a public-facing brand check.
JHX: What does public mean?
JHD: From outside of the class body.
JHX: In this case we only need it inside lexical scope.
JHD: But this proposal would permit it.
JHX: I don't think it's necessary to expose it to the outside.
JHD: All of the syntax suggestions would be very confusing if they weren't available outside of the class body. I think the only syntax that is intuitive to limit inside the class scope is private fields. My view is the only syntax that wouldn't have confusion limiting inside the class body is private field syntax.
JHX: Why?
JHD: Because otherwise we need to invent a whole new syntax. You brought up a whole bunch of concerns about confusions of syntax, and those would all be worse than private fields.
JHX: I don't think so. #13 doesn't rely on private fields. What people need real instanceOf. If they need real instanceOf, they have to abuse private fields.
BFS: Just a question, what happens if you have a partially initialized object? It was constructed with the class constructor but it never finished installing private fields because of a thrown error.
JHX: In the constructor?
BFS: This would require a class hierarchy. Say your super class throws.
SYG: I think what bradley is talk about is roughly like this: class C { constructor(){ throw something; } } class D extends C { #field = 42; constructor(){ super(); } }
if super throws an error, you will have a partially installed fields.
BFS: The key here is when the this
value from class C will be reachable even though it is not fully initialized, as is the case for DOM classes: class C { constructor(){ someGlobalRoot.lastInstance = this; throw something; } } class D extends C { #field = 42; constructor(){ super(); } }
SYG: You have the instance, but it lacks the class D private fields.
BFS: And it is still instanceof D
.
JHD: The only way to differentiate someGlobalRoot.lastC
from a “true” instance of D is a private field check.
BFS: It would be possible with the other one, but …
SYG: What does it mean to be a “true” instance?
JHX: ???
JHD: ???
SYG: Code would need to synthesize a private field just for the brand check, which seems undesirable.
JHX: ???
SYG: You can’t change your mind later, this is just how the language works.
BFS: It’s an edge case, but it’s not necessarily unique. We don’t have a mechanism to brand check, and SYG was suggesting that private fields are the only option.
SYG: Issue #13 is proposing a very different way to look at ECMAScript classes, which would be aligned with e.g. Java.
JHX: We are designing this feature for programmers, not spec writers.
JHD: JS programmers understand JS classes; other languages are not really relevant.
BFS: We’re trying to point out mechanical issues from something like #13. Private declarations are in the pipeline, and will have analogous behavior. Even worse is a nested class in which the outer class has a private field, and I don’t know how instanceof would handing them.
SYG: These mechanical issues seem fundamental to the language, and I don’t believe can be simply “worked out” from this point.
BFS: I think there could be a use for something like #13, but it doesn’t seem to preclude private field checks. Syntax aside, “is of” would be introducing a new kind of brand check and we would need to work out exactly what it means and its mutual exclusivity with the current kind of available brand checks.
JHD: Also, private fields are currently exclusive to classes, but there is desire for more and we want something that would work with them.
…
JHD: I don’t expect real people to write this code, but we must be able to explain every detail about how a new feature behaves anyway. For example, what if the D constructor throws after installing private fields but before running to completion?
JHX: I think the two cases can be the same.
SYG: [disagrees]
JHD: [disagrees]
SYG: Your proposal is that someGlobalRoot.lastInstance is an instance of D only if the D constructor runs to completion?
JHD: The mental model must be complete in the spec.
JHX: I don’t think a perfect mental model is possible. But behavior can be exactly the same.
SYG: So concretely, you object to the syntax but not the semantics? What is your objection to the syntax? In plenary, no one else found it confusing.
JHX: We should listen to the community, and do some research. On the mental model in this area.
BFS: As observed in the research calls, we can only get vague feelings. Meetings like this focus on the mental model, but in research surveys it tends to be all over the place because everyone approaches it in their own individual way. Ergonomics, aesthetics, and surprise are measurable, but not mental model.
SYG: JS has no good example of a “real instance of”. What we have instead are brand checks. A proposal to add that would be orthogonal to this one, because brand checks aren't going away. It wouldn’t make sense to hold up this proposal on that future.
JHD: I don’t think having more than one way to do something is bad; we do that all the time.
JHX: If we test a single field, it’s wrong to infer more.
BFS: We’re criticizing solutions before agreeing on the problem. JHD is proposing a way to check for private field presence, nothing more. We use super-override to install a private field on objects we don’t own.
JHD: I agree with you that assuming private field presence implies instance-of-class is ill-motivated and such cases would want your hypothetical proposal, but this is different.
JHX: This is why I want research.
BFS: We can do a research call, but these are very different proposals. We actually use code like https://gist.github.com/bmeck/3955e617be395094432f4a3ceab23de7 .
JHX: That seems like WeakMap.
BFS: Yes, but we don’t want the private field to go away when the constructor gets garbage-collected. It can be observed by instrumentation, and also by anything propagated from the class with lexical access to the private field.
JHX: I need time to digest.
JHD: This has already been raised at two meetings; it would be great to finally see something happen at the next one. We can schedule another call if necessary.