tc39 / proposal-optional-chaining

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

Syntax: Use ?& (or anything else that correct the inconsistency between a?.b and a?.[b]) #34

Closed claudepache closed 5 years ago

claudepache commented 6 years ago

After careful consideration (see in particular #5), I think that the best syntax satisfying the difficult constraints we face (strong BC, consistency) is the following:

a ?& . b    // instead of   a ?. b
a ?& [ i ]  // instead of   a ?. [ i ]
a ?& ( x )  // instead of   a ?. ( x )

Pros

Cons

About the choice of ?&

rattrayalex commented 6 years ago

@levithomason much as I am a fan of polling, I think it's @claudepache 's call; community input is only one kind of input 😄

levithomason commented 6 years ago

While I agree community input is only one kind of input, I think we've exhausted useful input and analysis and it is time to make some decisions.

To recap some history, the conversation as to why not just ? started in Feb 2016, the concern against the dot after question mark syntax was opened/closed in June 2017 and re-opened in July 2017 due to "...people(in other issues) have expressed interest in having this debate again...".

I think we've successfully debated and analyzed the issue and it is well documented for others (mostly in #5). We considered other languages, usage statistics, symmetry, parsing, convenience, beauty, etc. There have been no new syntax proposals nor new issues with the current proposals in recent times. However, we are seeing lots of repeat comments/issues and restating/linking to previous conversations.

We're back to ??, which I'd proposed as a solution to the usage consistency issue a couple months ago, "This leads me to an operator like ??".

I'm all in favor of @claudepache (or whoever is responsible) taking it from here. However, I would like to make an effort to end the circles. 😅

claudepache commented 6 years ago

I'm all in favor of @claudepache (or whoever is responsible) taking it from here.

Option 2 seems to gain most favours, but it requires that null-coalescing uses another token than the one used most often in other languages (although, as said earlier, it could keep the same token, but it is probably not a good idea).

Because of that, I’m not willing to take such a decision alone. I expect to write a summary of the most reasonable/popular options with suggestion of choice, and let TC39 approve it.

(Also, reviewing the four options proposed by @rattrayalex, I don’t see why Option 1 did not use ?? for null-coalescing.)

Mathspy commented 6 years ago

Is merging the two proposals and going with ??., ??[, ??(, and ??: a possibility?

Mouvedia commented 6 years ago

I’m not willing to take such a decision alone.

What about taking it with @gisenberg which is behind proposal-null-coalescing?

andybarron commented 6 years ago

I very much support merging this with the null coalescing proposal, since they should share semantics and probably have similar-looking operators.

levithomason commented 6 years ago

What about |? for nullary coalescing? This is the F# null coalescing operator. Proposed here with reasoning and examples. Nicely complements the connotation of || in short-circuiting.

ljharb commented 6 years ago

Not bad, but then someone will ask for &?

levithomason commented 6 years ago

You mean && is to || as |? is to &?? Not sure what it would be used for.

If I had my way, I'd say, most other languages made ? work for optional chaining, make it happen. Then leave ?? for nullary coalescing. Seems this is the long defeated argument somehow, though.

xnnkmd commented 6 years ago

I think it is important to have syntax that is consise and recognizable for developers using elvis operator in other languages like c# etc.

E.g. a ?. b is much preferred over a ?& . b

gisenberg commented 6 years ago

@AndyBarron It might make sense to merge these proposals. My primary concern about merging them is hangups in syntax for one might hold up the other (eg: "should null coalescing work with null and undefined, or just undefined, or just null?" could potentially hold this proposal back for stage 2)

ljharb commented 6 years ago

Realistically, though, that question would hold back either proposal, since a very strong argument can be made that they should behave the same.

rattrayalex commented 6 years ago

Yeah, better to have them work well together and ship a few months later (from my perspective as an eager would-be adopter of both).

In any case, I think @levithomason was right that the maintainers should probably lock this thread for now. It does seem to have gone in circles (apart from the question of merging proposals, which arguably belongs on another thread anyway).

shicks commented 6 years ago

I'd be happy to see the ??., ??[, ??(, and maybe ??: discussed at the next TC39 meeting. But if there's concern about saving ?? for null coalescing, what about another alternative nobody's mentioned yet (as far as I can tell)?

Would it be reasonable to simply swap the order: .?, [?, and (?? Maybe I missed an earlier discussion where this was rejected, but it seems to me that it meets more of @claudepache's above criteria (at the very least, 1-6, though I'd argue for 8 and 9 as well) than the other options.

Repeating some of the earlier examples with this alternative:

foo.?bar[?baz].?qux(?)

Looking at this option, the one concern I would express is that (?) makes it more difficult to grep for nullary calls, but I don't see that as a dealbreaker.

ljharb commented 6 years ago

Possibly issues with 1. being a valid number literal?

shicks commented 6 years ago

That's a good point, though I still don't see it as a dealbreaker. It makes it slightly less consistent/beautiful, but in practice there should be no reason to want to write a number literal on the LHS of any of these operators, so it doesn't seem like a huge loss to forbid them (one could always use parens if necessary), and I believe getting this wrong would then still be a parse error?

I suppose the biggest wart in light of this would be that how the operator is parsed depends on the form of the LHS. The easiest way to implement it would probably be to add a modifier to PrimaryExpression to optionally exclude literals, and then propagate that up through CallExpression (or further, depending on whether assignment is supported). There seems to be some precedent for this sort of "production sniping" already.

ikokostya commented 6 years ago

Have you any proofs for impossibility of creation efficient parser for simple syntax ? https://github.com/claudepache/es-optional-chaining/issues/3?

All other syntax choices (e.g. ?&) look very weird and unreadable.

shicks commented 6 years ago

Sorry, I cannot provide any proofs - that degree of formalism is over my head. All I can point to is the intuition that the distinction in this case depends only on very local information (how was the token immediately to the left parsed) rather than information arbitrarily far away (is there a colon in this expression). So while I can't prove it, I'd eat my hat if it turned out not to be reasonably efficient to parse.

warent commented 6 years ago

Not the least of the issues with ?& is that your fingers have to stretch clear across a QWERTY keyboard to even type it up. It's like doing a bizarre dance of bouncing fingers back and forth which will become really obnoxious long term. Also for those of us who use our right hand for SHIFT, this is overall a really uncomfortable character combo.

ljharb commented 6 years ago

JS isn't optimized for "how easy it is to type on a single arbitrary keyboard layout", especially since people across the world use many different keyboard layouts. That should not be a consideration whatsoever, imo.

damieng commented 6 years ago

@ljharb Actual human usability should always be a consideration of a programming language if you want widespread adoption.

ljharb commented 6 years ago

@damieng absolutely it is! However, let's not anglo-centrically conflate "human" with "uses QWERTY".

damieng commented 6 years ago

It's an anglo-derived language with English keywords... Additionally the same character twice ?? will always be easier unless there is a key layout where ? is a multi-key sequence where & is not. (I'm not aware of such a layout myself)

ljharb commented 6 years ago

Certainly the same character twice will be easier :-) the issue there, as stated many times, is that ?? would necessitate ??./??[/??(, which people seem to find distasteful.

shicks commented 6 years ago

Let's not forget that code is read much more often than it's written. If we're going to optimize for any sort of ergonomics, it should be for what reads more easily, not what's easier to type.

staeke commented 6 years ago

A comment from a non-English keyboard user: I, and many I know, switch keyboard layouts constantly. Pretty much all major programming languages have been designed for a US keyboard layout so I switch to that whenever I do programming. It’s simply MUCH faster. And I really think it’s worth learning a secondary keyboard layout for this. To have common characters easily typed is crucial. THE most important aspect imo. Latin alphabet keyboard layouts have many similarities as well. Dot (.) is almost always easy to type though.

levithomason commented 6 years ago

Curious, do we have defined criteria for what constitutes a decision on this?

claudepache commented 6 years ago

Curious, do we have defined criteria for what constitutes a decision on this?

Decisions (about important/contentious points of proposals) are made by the TC39 committee, which is the body responsible for developing ECMAScript. I think they work by consensus.

According to the document describing their process, syntax is expected to be well-defined at Stage 2.

dfahlander commented 6 years ago

For the sake of intuitive and ergonomic coding and code reviewing, I'm in favour of adopting the ?? operator for this proposal and change nullish-coalescing to use a tertial pipe operator |||.

hax commented 6 years ago

I'd like to add an new syntax option:

!. ![] !()

Pros

All pros of ?& apply.

And it's only use one extra char ! so it's the most terse syntax in all syntax options.

Easy to remember (postfix ! can be understand as the abbr form of !=null) and maybe extended to other operator proposals in the future like x !? y : z.

Cons

TypeScript already use postfix ! for non-nullish assertion.

But there are two very GOOD news for TS:

  1. Though they have different semantic, but the old semantic and runtime behavior is compatible with the new semantic, because non-nullish asserted expression have the subtype of the nullish one. That means all current TS codes do not need any change for the new TS compiler which treat the operators as new semantic if you don't mind some strict null check warning.

  2. It's easy for TS to change non-nullish assertion syntax to !! which already allowed and effective! So it's very easy to upgrade old code manually or with tools, even now!

As @claudepache 's criteria

backward compatible (i.e., something that does not have currently another meaning, or at least that is so obscure that it is practically unused) — because this is a strong requirement for web browsers for reasons;

Yes

reasonably easily parsable (e.g., not something that requires infinite lookahead);

Yes. And TS/Babel 7 already support parsing it.

works for static and dynamic property accesses, and function calls, i.e. x.y, x[y], and x(y) — because I want to support the three cases;

Yes

not used in mainstream languages for other purpose, e.g.: ?? or ?:

TypeScript use it for non-nullish assertion. But the semantic is related and the runtime behavior is compatible.

uniform across the three syntactical cases;

Yes

suggestive — for instance the symbol ? may suggest “something with null” or “something conditional”;

Yes. Postfix ! can be thought as “if something is not null then...”. (And postfix !! can be thought as “something is definitely not null then” for TypeScript revised non-nullish assertion syntax)

has precedent in other languages, typically: ?.

Don't know. And see TS parts.

beautiful;

Don't know how to estimate this, but it's ok for me compare to ?& or other options.

easy to type.

Very.

Tiedye commented 6 years ago

@hax An issue I see with !., ![], and !() is the exclamation mark usually implies inversion of some sort. There there will be none here, which could be confusing.

hax commented 6 years ago

@Tiedye While I should already point out that:

Postfix ! can be thought as “if something is NOT null then...”.

In fact, if you consider the current proposals: a ?? b means a if null fallback to b, shortcut to a if a is not null a ?. b means a if not null then a.b, shortcut to a (null) if a is null

You will find that the ? meaning is conflict and confusing 😁

I don't treat such small inconsistent a real problem, but !. is more logical if you really think of it deeply... After all it just a transition from TypeScript "non-null assertion" to "non-null chaining".

littledan commented 6 years ago

I'm confused about the discussion of ??. in this thread given the parallel proposal of ?? as the nullary coalescing operator. Are proponents of ??. thinking that nullary coalescing would use a different syntax? Otherwise, are you OK with using whitespace to differentiate the two, as mentioned in this comment?

In my opinion, that path would be pretty confusing. I thought, at the time, Waldemar was raising it just as a theoretical example rather than what he actually preferred. Real confusion here seems likely. For an example of two similar things that are interpreted differently in Waldemar's suggestion (by design),

. does allow for whitespace on both sides, and you can put whitespace before a square bracket for property access. This suggestion depends on whether you have whitespace between ?? and [, not whether you have whitespace on the sides of it, as in those cases. But, given how ?? is designed to be composable with other elements [, . and (, it might seem like they are separate tokens conceptually and that you are allowed to place whitespace in the middle.

alangpierce commented 6 years ago

@littledan My reading of the discussion above is that ??: is the front-runner for nullish coalescing (if optional chaining ends up as ??.), at least going by thumbs-up reactions: https://github.com/tc39/proposal-optional-chaining/issues/34#issuecomment-332649067 https://github.com/tc39/proposal-optional-chaining/issues/34#issuecomment-333413308 I certainly find it much more clear than trying to make ?? work alongside ??., ??[, and ??(.

littledan commented 6 years ago

@alangpierce Oh, the idea is that nullary coalescing uses ??:? Oh, sorry for my misunderstanding; that sounds pretty reasonable.

TheNavigateur commented 6 years ago

?> https://github.com/tc39/proposal-optional-chaining/issues/5#issuecomment-353590806 https://github.com/tc39/proposal-optional-chaining/issues/5#issuecomment-353768587

claudiopro commented 6 years ago

@claudepache @gisenberg will you represent this proposal at the TC39 meeting in March? 😄 sorry for the question out of context but I didn't think this justified opening an issue. Apologies if logistics around the proposal are discussed in another forum.

leggsimon commented 6 years ago

I'm actually interested as to why syntax like Ruby's hasn't been suggested (&.), unless I'm missing something.

Considering, as far as I can tell at least, this proposal essentially replaces this

var street = user && user.address && user.address.street;

In my mind it would make sense that the syntax is somewhat similar. For example:

var street = user&.address&.street;

One other reason I prefer this over a ?. is it would remove any possibility of allowing ? in IdentifierNames in future versions of ECMAScript. I've outlined this in an, admittedly unpublished, proposal.

Although I recognise that my proposal of allowing ? in IdentifierNames doesn't drastically alter the language or add any really fancy "new feature" but I think it massively aids readability which in my mind is as valuable as any "feature". Sadly most of the syntax proposed here would put a complete end to that ever being included in JS.

I'd like to hear some thoughts as to whether that had been considered or any reason why I have misunderstood something. (Also any comments on my proposal would be welcome)

ljharb commented 6 years ago

We’d also need &[ and &(; I’m not sure how that works with the bitwise operator and existing grammar.

Separately, ? is almost certainly never going to be allowed in identifier names; it’s being considered also for the partial application and pipeline proposals.

littledan commented 6 years ago

@gisenberg presented ??. to TC39 in January 2018 in a Stage 1 update. The response seemed mostly positive to me. Should we update the explainer and spec text to switch to this option?

TheNavigateur commented 6 years ago

@littledan Do you still like ?> ? It's the one I prefer the most

claudepache commented 6 years ago

@littledan

@gisenberg presented ??. to TC39 in January 2018 in a Stage 1 update. The response seemed mostly positive to me. Should we update the explainer and spec text to switch to this option?

Was the syntax for nullish-coalescing also discussed? Because it would be unfortunate if a??[b] and a ?? [b] have two radically different meanings.

jridgewell commented 6 years ago

Was the syntax for nullish-coalescing also discussed?

Yes, ??:

hax commented 6 years ago

@littledan I hope the committee have the chance to check all syntax options: ??., ?&., ?>., !.

littledan commented 6 years ago

@gisenberg just presented ??., as it seemed to be the favorite of this group.

Generally, it's hard to be productive doing this sort of bikeshedding in committee in TC39. It seems reasonable to me to do it mostly offline as has been done in this thread.

codehag commented 6 years ago

I want to echo @leggsimon and propose

&.

Context: In ruby they were unable to use the ? operator and opted for & instead. The discussion is here: https://bugs.ruby-lang.org/issues/11537#note-11

a && a.b // becomes a&.b

Criteria:

1) backward compatible (i.e., something that does not have currently another meaning, or at least that is so obscure that it is practically unused) — because this is a strong requirement for web browsers for reasons;

This I'm not 100% sure about, as im not sure if the &. operator was already discarded. But from my perspective I believe it is backwards compatible as there is no existing syntax like this. while there is the bitwise operator &, it is not used in conjunction with ., ( or [ and unlike the ? it is not used already in statements where this kind of syntax may be frequently seen, such as a && a.b ? "foo" : "bar";

Edit Note: i was totally wrong about bitwise operators!

2) reasonably easily parsable (e.g., not something that requires infinite lookahead);

Look ahead would be 1 character

3) [...] works for x.y, x[y], and x(y);

as long as the next character is not a space or another &, we can check if it is a [, ( or .

it would look like this:

x&.y
x&[y]
x&(y)

4) not used in mainstream languages for other purpose, e.g.: ?? or ?:

used in ruby as a safe navigation operator, which is very similar to this use case

5) suggestive — for instance the symbol ? may suggest “something with null” or “something conditional”;

suggestive in that it reflects the currently used pattern a && a.b becomes a&.b

6) has precedent in other languages, typically: ?.

ruby, as mentioned above, uses this as their the safe navigation operator, which is a very similar use case to this one

7) beautiful; 8) easy to type.

a matter of taste I think

The Pros and Cons:

Pros

Cons

Sorry if this has been proposed before, I tried to find a reference to it if it was ruled out already but I couldn't find anything!

claudepache commented 6 years ago

@codehag This is not backward compatible: the expression x&[y] has already a well-defined meaning today.

codehag commented 6 years ago

ah you are right. could we think about it differently then -- I saw in the proposal that ?. is always with the dot operator, perhaps the same could be applied to &.?

hax commented 6 years ago

I saw in the proposal that ?. is always with the dot operator, perhaps the same could be applied to &.?

So it lose the benefit of "Single character" and "easy to remember/type" compare to current ??. ??[] ??(). Up to now, only my proposal of !. ![] !() can really use only single char 😄

codehag commented 6 years ago

I had a chat with littledan in another channel and I wanted to add it here so that if anyone else has comments they can chime in:

My concern with the ?? is that, from my perspective the case where this would be most useful for me (speaking very subjectively) would be this:

a && a.b

this is something that happens all the time. It is rarer to have something like this

a.b && typeof a.b === "function"

it is also rare to have this:

a.b && a.b[1]

So for this reason I prefer the &. operator, even though it is not as nice as the other cases with the ??

here is a comparison:

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

foo&.a
foo.a&.(b)
foo.a&.[b]

And again, &. is winning out for me here because it is filling a use case for something that I use very often

however, like i mentioned this is super subjective, and i wish there was a simpler solution. I agree that what I am proposing is not ideal. Do we have any user data regarding how much need there is for these different cases?