Skip to content
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

discrepancy: we're allowed to get/set private fields, but not public fields, and public auto accessors are not fields. #550

Open
trusktr opened this issue Oct 17, 2024 · 1 comment

Comments

@trusktr
Copy link
Contributor

trusktr commented Oct 17, 2024

Note

This post comes after experience using decorators with TypeScript and Babel, including the new Stage 3 decorators since day one, for years.

It seems to me that the argument for performance in not allowing class fields to be accessed with (or converted to) get/set pairs is moot, because accessor #foo = 123 is exactly equivalent to the very same idea, and yet we allow it.

The problem

In this code,

class Foo {
  accessor #foo = 123 //  this creates a `get`/`set` pair *somewhere*!

  accessor foo = 123
}

The #foo and foo properties are not the same at all. The private field is associated with the instance, while the public field is defined on the prototype.

This is a big discrepancy.

First and foremost, converting foo = 123 to accessor foo = 123 can, and will, break certain code bases.

The half-way defined accessor feature (when decorators are released, the feature will be half-way implemented, with the other half in a separate spec) does not even need to exist in this round of decorators, because if we simply fix the timing of context.addInitializer() for getter/setter elements, as described in

then, for the most part, important use cases that include reading initial values from getters/setters are covered. Please show a case where you absolutely need the getter/setter extra initializer to run before fields.

Don't get me wrong, accessor syntax is concise and more enjoyable than getters/setters, but not fundamentally enabling anything new, while decorators provide new confusing differences between auto accessor and regular accessors as in #548.

Solution

It would be more desirable, more consistent, and more breakage avoiding, to be able to provide the ability to provide get and set functions for class fields, with the same or similar semantics as private fields which we've already blessed.

Two ways to do this:

  • Option 1: The simplest option is perhaps to update the [[Define]] semantics of field initialization so it creates an accessor descriptor if any decorator has provided the get or set functions, otherwise continue with a value descriptor as before.
    • This will share the get and set functions across instances
  • Option 2: Keep the descriptor as a value descriptor, while mapping the get/set functions to inaccessible internal/private storage (like private fields).
    • If someone overrides the field with their own accessor descriptor, we could either
      • let the get/set functions continue to be used by any other code referencing them (silent fail)
      • or throw an error

Regardless of which of the previous two are picked, then if we also:

then at this point class fields would be as useful as accessor including with initial values, which would effectively be eliminate the need for accessor in this iteration of decorators.

Accessors would still be nice sugar for prototype getters/setters, but basically unnecessary for shipping decorators.

@pzuraq
Copy link
Collaborator

pzuraq commented Oct 17, 2024

@trusktr so I've been trying to tell you a few things for a while now, gunna lay it out one more time.

  1. I know the performance concerns don't seem to make sense to you from time to time in this design. They also did not make sense to me. A lot of this I believe came from the uncertainty of dynamic class features and behaviors that engines only realized once they had started implement class fields with [[Define]] semantics and saw that they were huge performance regressions initially. So I think they basically adopted a "let's play it extremely safe" stance, which meant that they either did not want decorators at all, or would only accept a version where as much behavior as possible was statically knowable at parse time.
  2. The changes you keep suggesting at this point in the process would require that the stage 3 spec be moved back to stage 2. At that point, it could once again be challenged by any TC39 member and potentially completely halted in progress. It could be killed, because stage 2 is a lot less certain than stage 3.

I have and the other champions have no control over 1, and we are not willing to risk the consequences of 2. I understand your frustrations, but this is the best spec we could have had given the constraints and the fact that there were a number of members who were almost ready to kill the proposal entirely. It was frankly a miracle that we got consensus to have the features and capabilities we have.

@trusktr trusktr changed the title discrepancy: we're allowed to get/set private fields, but not public fields, and auto public auto accessors are not fields. discrepancy: we're allowed to get/set private fields, but not public fields, and public auto accessors are not fields. Oct 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants