Skip to content
This repository was archived by the owner on Jan 25, 2022. It is now read-only.
This repository was archived by the owner on Jan 25, 2022. It is now read-only.

Summary: Objections to fields (as opposed to alternatives), especially the private field syntax #150

@mbrowne

Description

@mbrowne

Continuing from #100 and other threads, here's a summary of key objections to this proposal raised by the community:

@hax's top 3 concerns:

  1. TC39 underated the risk of community break which is very harmful to all of us.
  2. TC39 current process failed on such controversial problems.
  3. Some TC39 members use a vicious circle and/or double standards to dismiss the issues/alternatives other raised/offered.

Also, he believes another long wait for private state is acceptable if that's what it takes to get it right: the problems with the current proposal—including with public fields—are just too severe.

Regarding the substance of the proposal:

  • Duality of private vs. public fields will cause confusion: similar syntax but very different semantics
  • # syntax does not fit into the mental model of JS devs and will cause a community split, and TypeScript issues will further fracture the community
  • We don't need public property/field declarations and if we must have them, they should follow existing property semantics instead of fields. Fields cause pernicious bugs when overriding properties in subclasses or refactoring base classes.
  • Classes 1.1 proposal offers a better alternative in many ways, including instance variable semantics

@rdking:

  • Similar concerns about the process as @hax. Difficult to understand the committee's requirements and the reasons for them.
  • "Undetectability" should not be a requirement since it falls short of a fully protective security feature
  • Strongly believes that the best solution will integrate with existing features instead of crippling or disabling them, e.g. inconsistency of obj['property'] for public fields but no equivalent for private fields breaks existing feature by breaking expectations. Lack of dynamic access of private fields (e.g. this['#x']) is a deal-breaker.
  • # is not "well-defined"—has two meanings. Context is insufficient to disambiguate declaration and access.
  • Advocates property semantics instead of field semantics (but somewhat differently from @hax; see Can we take a step back? #144)

@bdistin:

  • This proposal lacks long-term planning and will irreversibly reduce the design space for important future proposals such as keywords for other access modifiers
  • Agrees with @rdking that lack of dynamic private properties is a deal-breaker; violates core strength of the JS language (dynamicism)

@mbrowne (me):

(NB: it's mbrowne, not mbrown)

  • This is a solid proposal as-is, but agree with @bdistin's point about long-term planning
  • Strongly agree with @hax that declarations should use property semantics, specifically the part about using [[Set]] instead of [[CreateDataPropertyOrThrow]], for the reasons described in Field declarations overwrite properties on the prototype #151 (comment) and Can we take a step back? #144
  • private #x syntax should be strongly considered because # alone might make future native support of intermediate access levels impossible. But # alone might be OK if we are confident we could have another way of natively sharing private fields within a module.

@Igmat:

  1. agree with @hax about somewhat failed process for such controversial topic
  2. brand-checking shouldn't be added implicitly to all private reads/writes, since it breaks metaprogramming with proxies as described in Private members break proxies #106 and [Private] Metaprogramming vs Security #134
  3. strongly agree with @hax about that [[Set]] should be used instead of [[CreateDataPropertyOrThrow]]
  4. agree with that current proposal should allow future native expansion in some way (there are a lot of ways to achieve that)
  5. Symbol.private + some kind of shorthand syntax for making symbols more ergonomic, provides much cleaner mechanism for encapsulation

@shannon:

  1. # being part of the name leads to confusion because this.#x !== this['#x'], it's just too weird. The sigil is fine but the functionality is just too different.
  2. No dynamic access, no destructuring is a deal breaker for me
  3. I agree with @Igmat that "brand-checking shouldn't be added implicitly to all private reads/writes"
  4. I agree with @Igmat that "proposal should allow future native expansion in some way (there are a lot of ways to achieve that)"
  5. I agree with @rdking that "the best solution will integrate with existing features instead of crippling or disabling them."
  6. I believe a private symbol approach (as described in syntax 1 here [Private] yet another alternative to #-based syntax #149) is by far the simplest addition to existing JS paradigms/existing JS class spec, and achieves most of what the current proposal wants with a few minor exceptions (possibility to leak private symbols for one, but I think this could actual be useful for things like protected to be implemented in userland).

@aimingoo:

  • Concept "Fields" is unclear and its necessity as an independent concept is questionable. The concept undermines the "Object is collection properties" core concept, and the impact will be extremely far-reaching, but nobody taken seriously. The Similar sound includes: Not Fields in Classes 1.1 proposal.
  • Using the lexical environment to implement "private field" is to recreate var and ctx's VariableEnvironment, which is an abuse of Environment components, and it is obviously too bulky.
  • The syntax is very unfriendly, especially with # as a prefix character for declaring fields and for name operations (such as the semantics of this["#x"] vs. this.#x). About grammar, I recommend enabling the private keyword to declare private properties (Note: that I don't support new concepts like "Fields or Private Fields"). And # as an operator, this is reasonable in both this#data and #data as unary or binary operators.

Reference: #148 , #100 (comment)


@RyanCavanaugh:

  • The choice of [[Define]] over [[Set]] for initializers is a bad trade-off that throws away six years of evidence from TypeScript and Babel developers' use of fields. The "natural experiment" has been performed, the results are clear, and the runtime breakage incurred here is very difficult to detect with tooling. The proposed upside of [[Define]] (const fields later) is purely speculative; the downside of not being able to install a deprecation setter is concrete and immediate.
  • Making initializers on fields optional, especially combined with the above, is unintuitive and dangerous. This syntactic expansion isn't strictly necessary and represents a substantial breaking change problem for TypeScript/Flow/Babel with no clear upside.
  • Honestly, the negative response to the # sigil is something we should just ignore and take the hit for, if built-in hard privacy is really needed. People will adapt and the runtime need for it is extremely clear; all counterproposals have been ignorant of the design constraints or runtime semantics.

@Jamesernator

my main objection to the current private fields proposal (and more so private methods) is that it throws away the notion of prototypal inheritance in favour of an object branding mechanism inconsistent with how other properties work.


In addition, some members of the TC39 committee also have current objections to this proposal. For example:

@allenwb:

See the Classes 1.1 motivation document. In particular if you negate the descriptions in the Design Rules bullet list you have a good summary of my concerns with the major problems being:

Design Rules:
Item 2:

Be as small as possible

Item 3:

Support a user conceptual model that is as simple as possible. It should be easy to teach and easy to understand.

Item 4:

Be internally consistent, with few, if any, special cases or unexpected feature interactions.


@zenparsing:

I believe that we are overpricing the benefit of this entire feature set while underpricing the risk.

Why do I think that we're overpricing the benefit?

  • In my experience, most of our constituency does not need hard-private in their day-to-day programming work. Hard private is important for a small number of use cases, such as platform library code and high-profile libraries which are especially subject to breaking consumers when implementation details are updated. Most application programmers I know don't write that kind of code. Sorry 🤷‍♀️
  • Hard privacy can already be achieved with decent ergonomics. See https://github.com/zenparsing/hidden-state#example, for example.
  • Folks that really want "fields" are mostly happy using TypeScript already. It doesn't seem implausible to me that TS could have an option for generating hard-private code for private x, perhaps with some optimization work applied to WeakMap on the engine side.

Why do I think that we're underpricing the risk?

  • We know that many devs don't like the syntax, and don't understand why the syntax that they enjoy using (private x from TypeScript) won't work. It doesn't "just work". We are taking on the risk that this feature will continue to create head-scratching across our community.
  • We're taking on the risk that we'll want # for something else and it won't be available.
  • We're taking on a small amount of ASI risk.
  • We're taking on a risk that by pushing something unpopular our community will lose some amount of faith in TC39 and the future of JS.

I probably missed something important, and obviously I haven't included a summary for everyone who has commented. If you feel something is missing, please provide a concise summary of your feedback as your first comment on this thread (saving longer arguments for subsequent comments). Also feel free to simply say, "I agree with [username]".

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions