tc39 / proposal-optional-chaining

https://tc39.github.io/proposal-optional-chaining/
4.94k stars 75 forks source link

Poll: Operator Syntax #51

Closed gisenberg closed 5 years ago

gisenberg commented 6 years ago

Hey folks,

I wanted to pull out and highlight the options that have been raised in the syntax thread, as not all options were presented and they are now somewhat buried. Please use the response buttons to vote and keep comments related to syntax in #34

gisenberg commented 6 years ago

?.., ?.() and ?.[], with null coalescing taking the ?? token

gisenberg commented 6 years ago

!., !() and ![] with null coalescing taking the ?? token

gisenberg commented 6 years ago

?&., ?&() and ?&[] with null coalescing taking the ?? token

gisenberg commented 6 years ago

?>., ?>() and ?>[] with null coalescing taking the ?? token

gisenberg commented 6 years ago

?., ?.() and ?.[] with null coalescing taking the ?? token

gisenberg commented 6 years ago

??., ??() and ??[] with null coalescing taking the ??: token

TheNavigateur commented 6 years ago

\., \() and \[] with null coalescing taking \\

Tiedye commented 6 years ago

:?., :?() and :?[] with null coalescing taking the ?? token

Kerrick commented 6 years ago

~., ~() and ~[] with null coalescing taking the ?? token

jrista commented 6 years ago

Why is there not an option for:

?., ?(), ?[]?

This seems like the most natural approach. Throwing a . between ? and () or [] is very syntactically strange.

gisenberg commented 6 years ago

@jrista Please see https://github.com/tc39/proposal-optional-chaining/issues/5#issuecomment-311795543 and https://github.com/claudepache/es-optional-chaining/issues/3 for additional context. The obvious solution is not an option.

EDIT: Also, see https://github.com/tc39/proposal-optional-chaining/issues/52

jrista commented 6 years ago

Thanks.

kacgrzes commented 6 years ago

I believe we have a clear winner here. Following Optional chaining in Swift and Safe Calls in Kotlin, ?. seems to be the way.

ljharb commented 6 years ago

For better or worse, specs aren’t decided by a popularity contest. ?. is inconsistent and is almost definitely not going to be able to achieve consensus (it’ll get its fair shot, but I’m trying to set expectations)

scottrippey commented 6 years ago

Is it syntactically possible to allow this syntax? a && .b, a && .[i], a && .() This could be extended to ternaries too, like a ? .b : 0

claudepache commented 6 years ago

Is it syntactically possible to allow this syntax? a && .b, a && .[i], a && .()

Probably, but Optional chaining has different semantics than current && with respect to short-circuiting: Current && operator checks for falsy, while optional chaining checks for nullish.

(I’ve proposed to use ?& instead, but it didn’t have much success.)

Mouvedia commented 6 years ago

?., having to surround the expression with parentheses for ?[] and ?()
(with null coalescing taking the ?? token)

FranklinYu commented 6 years ago

.?., .?() and .?[] with null coalescing taking the ?? token

mentioned in https://github.com/tc39/proposal-optional-chaining/issues/34#issuecomment-371910291 by @hax

ScottRudiger commented 6 years ago

@ljharb

For better or worse, specs aren’t decided by a popularity contest. ?. is inconsistent and is almost definitely not going to be able to achieve consensus (it’ll get its fair shot, but I’m trying to set expectations)

I think it's been established that there's likely no option able to achieve complete consensus (i.e., unanimous). But, there's an option capable of satisfying most.

"[W]e are unlikely to satisfy everyone." - gisenberg

"I realize that it's impossible to satisfy everyone [...]." - hrishikeshs

"I had to admit that all alternatives may have pros and cons, which can not satisfy everyone [...]." - hax

"It seems pretty clear that there is no option which will get absolute consensus as the top choice among everyone participating in this thread." - littledan

"No operator proposal satisfies everyone (yet), it seems. That's because every proposal has tangible drawbacks vs one or more of the others (whether you like to admit it or not)." - TheNavigateur

"[Yet,] it's also possible that this is going to affect millions of JavaScript developers." - damieng

"[...] I believe [the option] most likely to satisfy the majority is ??. with nullish coalescing taking the ??: token." - gisenberg

"I think many might agree that if it wasn't for the ?. ?.[ ?.( inconsistency factor, ?. is one of the more optimal choices." - me

"[M]any programmers don't find the inconsistency of a?.x a?.[y] a?.() in the first place." - hax

"[...] It sure looks like I am not the only one. #51 shows that the current implementation (?.) is still the most popular one, while the new proposal (??.) appears to be rather unpopular." - lehni

The question is: the most of who?

Is the size of this group

1?
3-4? contributors/members involved in this proposal
30-50? TC39 members attending the next meeting(s)
200-300? real JavaScript users participating in this poll
2-6 million plus? highly conservative post-googling estimate of JavaScript developers worldwide
21 million plus? total software developers worldwide who might touch JS (growing ~1m/yr--and this may be a serious underestimate)

I'm not intimately familiar with the inner-workings of TC39, but I'd venture to guess the answer is realistically 30-50 with strong emphasis on input from 1-4.

If that's the case, I would hope that whomever is presenting this proposal next includes the results of this poll as significant evidence of the direction to take.

In any case, I think it's important for this discussion to be clear about who exactly it is you're striving for consensus with. Knowing the answer to that, our expectations may be tempered.

claudepache commented 6 years ago

The two most popular choices are, at the time of writing:

  1. ~90%: optional chaining: ?. / ?.[ / ?.( — null coalescing ??
  2. ~38%: optional chaining: ??. / ??[ / ??( — null coalescing ??:

The third one (?..) gained ~20% votes.

They are roughly the same two as in a previous poll, although in different order. (I say ”roughly”, because the choices in the previous poll had some differences relatively to this one.)

It seems clear at this point that we’ll pick one of those two options. Which one, will not depend solely on popularity, since we should strive to have what is the best for developers, not what pleases them the most.

TheNavigateur commented 6 years ago

Isn't what's best for developers the same as what pleases them the most, at least in the long term?

Otherwise how could you possibly define "best"?

Of course I accept that what pleases developers now may not please developers in the future, which is what I think your point is

claudepache commented 6 years ago

Isn't what's best for developers the same as what pleases them the most, at least in the long term?

Otherwise how could you possibly define "best"?

Of course I accept that what pleases developers now may not please developers in the future, which is what I think your point is

As a trivial example of dissonance between ”pleasing” and “best”, a developer may want x.y to ”just work” even when x is undefined, but not realising that it will cause them much headache when debugging any complex code.

For the particular case of Optional chaining, I am currently not sure what is the best. Different syntaxes, including ??., have been discussed since several months, and ??. has attained a rough consensus amongst those most involved in the proposal. Very recently (at most two weeks ago, after PR #48 has been opened), strong resistance has become manifest, and the debate in #34 became very heated. Some good points have been made, but it has generated more heat than light. We (those involved in the proposal design) need to keep a cool head and consider if the arguments recently made are enough to change the rough consensus.

TheNavigateur commented 6 years ago

"Headache" is not pleasing, so we are talking about the same thing, just from a longer term / wider perspective.

Otherwise there is no way of measuring "best".

The solution is probably to take a poll among those who have engaged fully in consideration & conversation about the various alternatives, which is what I think your point is.

felix9 commented 6 years ago

a.?b, a(?b), a[?b], a??b

noppa commented 6 years ago

It seems that the bind-operator might not be going anywhere (based on this issue tc39/proposal-bind-operator#53 and the closing comment on this issue Microsoft/TypeScript#3508).

Would the :: operator be up for grabs?

a::b, a::[b], a::(b) — null coalescing ??

I realize that people associate question mark with the optionality of the property access but meh, there have been suggestions for ! or \ around here too. I personally quite like how :: would look and it could help with, say, tc39/proposal-partial-application#21

claudepache commented 6 years ago

and it could help with, say, tc39/proposal-partial-application#21

In my opinion, the proposed example in that thread:

const curriedDoStuff = doStuff(?, v?.a ?? 0, v.b > 10 ? 10 : 0, ?);

does not need our help to be rewritten more clearly. Replacing ?. with :: would lead to:

const curriedDoStuff = doStuff(?, v::a ?? 0, v.b > 10 ? 10 : 0, ?);

which is only marginally better. On the other hand, better formatting the code can make a much bigger difference:

const curriedDoStuff = ($1, $2) => doStuff(
    $1
  , v?.a ?? 0
  , v.b > 10 ? 10 : 0
  , $2
);
ljharb commented 6 years ago

I don’t think anything would be likely get through committee without including a question mark.

obedm503 commented 6 years ago

I don’t think anything would be likely get through committee without including a question mark.

but since the question mark has been such a pain, maybe they would be open to :: or something else without it

ljharb commented 6 years ago

I find it helpful to remember that it’s not just different syntaxes competing with each other - that we’re also competing with “do nothing, the language is complex enough”.

In other words, alternatives still often need to have sufficient motivation that they’d be viable choices in their own right.

cxw42 commented 6 years ago

Very late to the party, but was -> ->[] ->() ever considered? I searched the issues and online but didn't find any discussion. I found a comment on the old ecmascript wiki that => -> confusion was undesirable, but they would have unambiguous contexts here.

If you can point me to an already-closed discussion, please disregard the rest of this comment :) .

Criteria:

1, 2, 3: ok

4 Used in C with respect to things that might be null, which is the same as here. This is different, but the difference is added safety rather than added danger.

5 Not entirely uniform, but Perl has used these operators for years without tripping over the lack of uniformity.

6 Suggests accessing one thing from another.

7 Precedent in related contexts from C and Perl

8 Doesn't trigger some of the ??:???()??[] concerns noted above and in other issues. Clearly distinguishable from ??:.

9 Very ergonomic - many millions of LOC have used it over the course of decades.

Thanks for reading, and for filling me in on what I'm not finding in my searches!

ljharb commented 6 years ago

note --> would be the start of an HTML comment, a pretty unfortunate and easy typo.

TheNavigateur commented 6 years ago
car->.ac
car->['ac']
car->().ac

seems about as good or worse than

car?>.ac
car?>['ac']
car?>().ac

which has been voted upon, but obviously I'm not sure how people would vote on -> itself

claudepache commented 6 years ago

@cxw42

Very late to the party, but was -> ->[] ->() ever considered? I searched the issues and online but didn't find any discussion. I found a comment on the old ecmascript wiki that => -> confusion was undesirable, but they would have unambiguous contexts here.

I don’t think that the visual similarity with arrow-function => is relevant, since it is used in completely different context. (If -> had been adopted, there could have been grammar ambiguities, however.)

But, much more concerning, is the obvious clash with the similar-written operator in PHP:

  JavaScript PHP
Property/member access a.b $a->b
Optional property/member access a->b

@ljharb

note --> would be the start of an HTML comment, a pretty unfortunate and easy typo.

As a heavy PHP user: no, the typo is difficult to make.

noppa commented 6 years ago

note --> would be the start of an HTML comment, a pretty unfortunate and easy typo.

@ljharb That would cause problems only if it's at the start of a line, in non-ES6 module environment and without support from any kind of rudimentary linter or editor tooling which would disallow that even today.

TheNavigateur commented 6 years ago

TC39 must thrust forward with ?? in my opinion, even though it has not been my first preference.

People new to programming and going straight to JavaScript will clearly prefer the consistency of ??. and ??( vs ?. and ?.(, and in my opinion, the language should cater its decisions weighted more towards the programmers of the future (which span an indefinite amount of time) and those whose first programming language is JavaScript vs the programmers of today, whose overall preference is finite time-wise, and based on their experience in other languages.

I would like TC39 to not waste any more time, also because if you took a poll about whether people would prefer ?? or no optional chaining at all, I think the answer would weigh towards ??, if not 100%.

For these 2 reasons, especially the first, I would like TC39 to not hesitate any longer.

jhpratt commented 6 years ago

because if you took a poll about whether people would prefer ?? or no optional chaining at all

But that's not the options. ?., ?.(), and ?.[] are (IMO) the leading candidates, with others still being considered, of course.

ljharb commented 6 years ago

@jhpratt that won’t work because some on the committee, myself included, insist on the same prefix in front of the access token: iow, X. X[ and X( - where X is ? or ?. etc.

shannon commented 6 years ago

Could we do ??., ??() and ??[], with null coalescing taking the ??? token

ljharb commented 6 years ago

That might be a possibility, but I suspect that would get a similarly lukewarm reception as https://github.com/tc39/proposal-optional-chaining/issues/51#issuecomment-371017987 did.

TheNavigateur commented 6 years ago

I do like the semantics of ??: though, as it reminds me of the "else" part of the already existing ternary expression, which this also evaluates to (if nullish).

davegregg commented 6 years ago

I've been following this proposal very closely since just after the proposal repo was created. As someone who teaches JavaScript to new developers on a daily basis, I have grown sensitive to a few things which can help or hinder language acquisition and reading other people's (or your own old) code.

Consistency

There must be a consistent approach here. ?. for dot notation and then ?.[] for bracket notation... is just inconsistent (as @ljharb chiefly has continually pointed out). This has always been my frustration with Ruby's safe navigation operator.

JavaScript has enough inconsistency as it is. I want to be able to teach my students what property accessing looks like and be satisfied that the basic principle of "dot notation vs. bracket notation" will remain sound – even when eventually they are introduced to (or stumble into) optional chaining.

Readability

#51 comment 371017987 (??., ??[], etc.) has a scannable uniqueness on the page that reduces the threat of evoking the idea of other operators (as the use of the characters !, >, \, :, ~, & could do), while at the same time positively evoking the idea of a question – and really well, seeing as we already associate a heightened idea of questionableness to ?? in human language communications, like chat or SMS. (Right??)

Further, you're not going to see two question marks back-to-back like this anywhere in JavaScript, and though this is also true for sequences like ?&, the use of two different characters compounds the lexical noise which non-alphabetical operators suffer from.

So, I think #51 comment 371017987 and #51 comment 412232012 are superior choices, despite the dissimilarity to other languages' constructs (on which topic I agree with @TheNavigateur's recent comment).

jhpratt commented 6 years ago

Just a general note, I think it's important to point out that the nullish coalescing operator implicitly depends on the result of this decision. For those favoring syntax that would result in using ??: for nullish coalescing, remember that there will be an assignment operator to match. Is ??:= really what you want?

Between the options of ??:= and ???=, I'd personally prefer the latter by far.

Just some food for thought.

TheNavigateur commented 6 years ago

Might be just me but I'm totally comfortable with ??:=

davegregg commented 6 years ago

If that's what we end up with, we can call it the Combover Zoidberg operator.

dwelle commented 6 years ago

Slight variation on @shannon proposal, leaving out the . in ??.:

??, ??[], ??(), null coalescing ???

obj??prop
obj??deep??prop
obj??[prop]
obj??call??()
cxw42 commented 6 years ago

@dwelle I think it's fine, but see https://github.com/tc39/proposal-optional-chaining/issues/51#issuecomment-412213235

I have a bold/foolish suggestion :) . Would the committee please pick a syntax and move on? Those of us who don't like the committee's choice can write Babel plugins to give us our preferred operator :D .

(Yes, I know forking a language is a Bad Thing. I also know that transpiling is here to stay, so perhaps we really could use it to relax some of the constraints.)

ljharb commented 6 years ago

@cxw42 if a syntax is picked, babel will drop support for the other ones - you won’t be able to use them moving forward.

Zarel commented 6 years ago

@ljharb Babel has a plugin system – anyone can write their own plugins for any syntax at all.

In addition, Babel is open-source, so the change is a pretty direct process of forking the official plugin and changing the syntax it supports.

This is what @cxw42 means by "write Babel plugins".

ljharb commented 6 years ago

@zarel no, anyone can write plugins for the syntax that Babylon supports. Babel intentionally does not allow wild syntax experimentation. Certainly you could fork, but you can do that now whether a decision is made or not.

jridgewell commented 6 years ago

I’m a core maintainer on Babel: @ljharb is correct here. The parser is not designed for custom plugins, only the transformer.