Skip to content
This repository has been archived by the owner. It is now read-only.

Feedback on alternatives? #4

Closed
ljharb opened this issue Apr 1, 2020 · 9 comments
Closed

Feedback on alternatives? #4

ljharb opened this issue Apr 1, 2020 · 9 comments
Labels
help wanted

Comments

@ljharb
Copy link
Member

ljharb commented Apr 1, 2020

Hi everyone! It'd be great to get as much feedback from the community as possible before this proposal advances to stage 2.

  • Do you like the proposed solution, #privateField in obj?
  • Do you have alternative suggestions that would retain the same encapsulation guarantees that private fields already have?
  • anything else?

(If you have thoughts on shorthand syntax, please add those to #2)

Thanks!

@ljharb ljharb added the help wanted label Apr 1, 2020
@bathos
Copy link

bathos commented Apr 2, 2020

I love it. Doing Web IDL implementations in JS, I end up having to decorate methods with brand check wrappers even if I use private fields (due to not wanting the TypeError message to reveal implementation details). So far I’ve addressed that by keeping a Weak collection in the mix even when private fields would have been sufficient for maintaining the actual private state.

This would make it more natural to drop the extraneous weak collection in favor of using private fields even in the condition for when we “manually” throw the “Illegal invocation” TypeErrors. One less moving part in the mix: 👍

Re: syntax — this seems intuitive to me (partly due to the hint of symmetry with typeof foo not throwing a ReferenceError when foo is undefined).

@bmeck
Copy link
Member

bmeck commented Apr 3, 2020

I can list alternatives I can think of?

  • Meta properties : #x.has(o) or #.has(o, #x) - from thinking of private fields as WeakMaps. Definite preference for #x.has of those 2. This still does not expose the value as first class, but if the value is first class as #x rather than a reference syntax, it would be a problem (same for current proposal).

  • Pseudo fn like import() : in(o, #x) - this has a serious downside of 0 in([], [1]) already being valid. This does not have problems with #x being a first class value rather than a reference syntax.

  • Disambiguate the operator between public/private : #x #in o - this seems weird, and I don't see reason to keep them separated currently except prototype crawling differences.

  • New contextual operator for own props using member expression akin to delete : own o.#x - shouldn't use has due to proxy trap naming being for in. Naming bikeshed. Could be useful, but seems a bit out of scope. Unclear if this is added why in wouldn't also be useful for code refactoring purposes.

@ljharb
Copy link
Member Author

ljharb commented Jun 7, 2020

The in solution reached stage 2.

@ljharb ljharb closed this as completed Jun 7, 2020
@lightmare
Copy link

lightmare commented May 30, 2021

I have a question and it probably doesn't deserve its own issue, so posting here.

Could this be solved with an additional check in optional chaining operator?
o?.#x doesn't seem very useful if it can throw. So what if it also checked the presence of #x before trying to access it? You wouldn't be able to distinguish between #x not in o and o.#x === undefined, but since you have full control over #x (right?), you can make sure it never becomes undefined. And then you can interpret o?.#x === undefined as missing.

@acutmore
Copy link

acutmore commented May 30, 2021

o?.#x doesn't seem very useful if it can throw. So what if it also checked the presence of #x before trying to access it?

If this change was made, returning undefined can also imply that the left-hand-side was null or undefined. So the full check would need to be:

const hasField =  o !== undefined && o !== null && o?.#x !== undefined;

And, as you say, this pattern would be limited to situations where the private field was guaranteed to never store undefined, which may not always be desirable.

@lightmare
Copy link

lightmare commented May 30, 2021

const hasField = o?.#x !== undefined;

Would give the same result every time. When o == null, optional chaining returns undefined immediately even before the additional check I suggested.

I was drawing from the rationale for this proposal, which asks for a way to silently "check if an object has a private field". null and undefined naturally don't have private fields, there's no discrepancy.

@acutmore
Copy link

acutmore commented May 30, 2021

Right you are, mine was unnecessarily verbose.

Might also be worth noting that this would be a breaking change for any code that is relying on invalid private field access throwing. It also appears this was discussed as part of the optional chaining proposal here: tc39/proposal-optional-chaining#28

@lightmare
Copy link

lightmare commented May 30, 2021

Thank you, that completely answers my question. This additional silent check was considered, and rejected in favour of consistency with other kinds of optional chaining. Which makes sense, even though none of the examples presented in that thread convinced me that o?.#x throwing is actually useful (quite the opposite).

@ljharb
Copy link
Member Author

ljharb commented May 30, 2021

It’s quite useful, and was a necessary part of the design of class fields - but that’s also irrelevant, since that proposal is stage 4 and this one can’t change it, for the reasons mentioned above.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
help wanted
Projects
None yet
Development

No branches or pull requests

5 participants