Closed hax closed 4 years ago
ping @DanielRosenwasser
Also a dupe of of discussion in #15 (with slightly different preferences).
While the conversation is still open, IMO, parenthesization is definitely the wrong choice, as no matter where you come from, that's surprising (afaik neither swift nor c# ever require parens, and I haven't seen another popular language that does). Intuition will come with usage over time, so long as any precedence is chosen, it will ultimately be fine (clearly - both swift
and C#
's ??
operators work), and any requisite linting/tooling will grow around that (as it is needed at either precedence, if you assume some subset of people will expect the other). Without choosing one and sticking to it, there is no opportunity for this intuition to grow and for the need for such tooling to decrease over time, which is just a waste of that time, tbh.
The current precedence was selected so that ??
is a likely "more-correct" drop-in replacement for ||
as a default-initializing pattern that's already in use in the ecosystem today. I find that to be a fine justification for it, as do others, I assume. Clearly arguments exist for both (as languages use both), however I think not selecting one is a disservice to the ecosystem as a whole, and its' ability to create its' own norms and expectations.
parenthesization is definitely the wrong choice
We already force parenthesization in mix of ??
and ||
/&&
case, and if use low precedence, we will never drop the limitation. And I'm not suggesting parenthesization for ever, I'm just asking it for postpone the final decision.
We already force parenthesization in mix of ?? and ||/&& case, and if use low precedence, we will never drop the limitation.
That's probably also a mistake from an intuition building perspective, but I'm also not going to insist it be re-litigated in favor of shipping what's done, for the same reasons (it ultimately doesn't matter, operator precedence is entirely arbitrary, just stick with one and be done with it). If you're about to cite **
, I also believe that forcing parenthesis around that was also a mistake, as it has prevented any kind of consensus forming as to handling it correctly without parenthesis, and nobody is looking to change that, which is ultimately what would happen here, too, which is very much not where this should go. If anything, past experience with **
has taught me that we absolutely can not ship without an arbitrary precedence selected, as once it has shipped, there's no drive to correct or extend it, and the underlying discussion will never progress.
Just poll within the tc39 - if more reps prefer either a tighter binding or looser binding (which, afaik, is what produced the current precence, but I could be wrong), and then go with that. As I said, it's arbitrary - there are theoretical "gotchyas" with any precedence, and requiring parenthesis just prevents any kind of intuition and tooling from building over time. Nobody's options are going to be changed W.R.T. preferring one precedence over another after shipping with parenthesis required - it's just masking a deadlock in the committee. I would rather you pick a random person out of a crowd who didn't know anything about programming and ask them to pick a precedence than to ship with parenthesis required with the intent of "kicking the can down the line", as that can will never be picked up.
and nobody is looking to change that, which is ultimately what would happen here, too, which is very much not where this should go.
My original issue has explained the plan : if the committee could adopt this solution, I'd like to write the future proposal of ??
precedence and present it in Feb 2020 meeting.
Just poll within the tc39 - if more reps prefer either a tighter binding or looser binding (which, afaik, is what produced the current precence, but I could be wrong), and then go with that. As I said, it's arbitrary - there are theoretical "gotchyas" with any precedence, and requiring parenthesis just prevents any kind of intuition and tooling from building over time.
I agree with that. Maybe the committee should first create a consensus what's the policy we agree on precedence issues. Whether past decisions of forcing parans were "mistake" we should never follow in the future.
It's probably worth mentioning that the current proposal is already shipping in chrome canary channel and the firefox beta channel (since this is/was planned to go stage 4 (meaning "in the upcoming spec") this week), so it's probably a little late to attempt to rehash something this core to the feature. I'm not personally familiar with the process, but I'm pretty sure this discussion was already had in the committee around the Stage 2 timeframe (ofc - the other issues were opened and you commented in them, so you're aware)... lemme find the meeting notes...here. A relevant quote:
DE: This is good for Stage 2. Suggest leaving same prec as ||. Expect lots of people to update their code from one to other. Would rather not go with exponentiation decision. Should just make a call on precedence. Shouldn't hang ourselves up and speculate too far in the future. Can leave this as open question for stage 2. Stage 2 is where we decide. We can flip flop on this.
And again later:
GI: So the developer intuition in the room matches giving lower precedence than ||
And most recently
JRL: We had a discussion on GitHub about disallowing those operators (?? and a comparison operator like == or >=) together. We decided not to do that because we that's not the way the current short circuit operators behave. You can freely mix || with comparison operators. You just need parentheses if you want to be more specific.
So while your comment history makes it plain you personally disagree with this choice of precedence, I think there's broad consensus that the current proposal is OK.
Many previous discussion (include first two you mentioned) of precedence only focus on mix of ||
&&
with ??
, not other cases. Especially the sentence of "So the developer intuition in the room matches giving lower precedence than ||" only discussed about ||
vs ??
, and current spec actually forbidden the mix which actually dismissed previous "dev intuition in the room".
IMO, the most recently response did not solve the comment of #48 and say nothing about other cases like a + b ?? c
.
So while your comment history makes it plain you personally disagree with this choice of precedence, I think there's broad consensus that the current proposal is OK.
I need to make it clear this is not my PERSONALLY disagreement, personally I'm ok to use tools to solve the confusion, but I discussed this with many developers, and many of them feel they do a little bit prefer high precedence and worry about no tools can protect the confusion now.
From a type system perspective, there is nothing wrong with this choice, it just doesn't provide enough protection as I originally thought.
Yes, TypeScript errs on the side of being permissive here. While I'm not a fan either, it's necessary to allow defensive checks from untyped/less-typed callers. But just like how an ESLint rule can require that operands need to be parenthesized, users can create semantic ESLint rules that require left operands of ??
must be nullish. I think there's definitely ways to mitigate confusion around some of of the ways ??
can be mixed with higher-precedence operators.
First I have to make apologize to the champions for submit this issue in the last minute. Though I feel current low precedence is contrary to the intuition of many programmers in the main use cases, after the last meeting, I planned to let it go, because I feel the problem can be solved by type system or linters.
I appreciate that you're being mindful here. I definitely understand that bringing these topics up is hard, especially for a proposal that has momentum at this point.
That being said, in the future I encourage you to try to bring up concerns and objections with stage progression sooner. At the last meeting I requested feedback on my intent to request stage 4 in December. Because we didn't receive objections in the meeting (nor soon after), we took that along with stage 3 as a signal for proposal stability on the TypeScript team. I'm sure this was the case for others as well, and we now have at least one shipped unflagged implementation.
Intuition will come with usage over time, so long as any precedence is chosen, it will ultimately be fine (clearly - both swift and C#'s ?? operators work), and any requisite linting/tooling will grow around that (as it is needed at either precedence, if you assume some subset of people will expect the other).
I tend to agree with this. I actually don't have a strong opinion on making ??
more broadly non-associative, but it really is worth stressing that both high and low precedence levels have been fine in these languages, and so we picked a low precedence because it was more common and makes it easier for some instances of ||
to be refactored to ??
. Our change to disallow mixing ??
with ||
was to prevent a different order of operations when those refactorings occur. Disallowing mixing ??
with more operators isn't at odds with refactoring, but ultimately it really doesn't seem like the current approach is even "wrong".
I think in practice, the potential trip-ups will be rare; however, if you'd like to discuss the matter, you can bring it up as I present at this week's meeting. I will leave the floor open to discussion since it is only appropriate, but will be seeking advancement if we as a committee still find the current proposal reasonable.
Hello Hax,
after the last meeting, I planned to let it go, because I feel the problem can be solved by type system or linters. I didn't expect this proposal to reach stage 4 so quickly that tools (such as ESLint) don't have time to provide protection in time
A small point to clear up and hopefully make you feel better about this proposal: it is to be expected that ESLint support for new features will not be available before Stage 4. In fact, ESLint's explicit policy is to explicitly wait for the Stage 4 signal from the committee before ESLint will land support.
So the fastest way to achieve the tooling support you desire is to advance the feature to Stage 4, which could happen today.
I think in practice, the potential trip-ups will be rare; however, if you'd like to discuss the matter, you can bring it up as I present at this week's meeting.
Thank you @DanielRosenwasser , I wrote a small slide: https://johnhax.net/2019/nc-p/slide
Not sure what time will the discussion, if I'm not online u could just use this slide which include almost everything I want to say. Thank you!
Hey @hax, I don't think I can present these slides on your behalf and do your arguments justice. If you can attend that would be the most ideal thing. If there's a time during this meeting that works best, I think we can potentially schedule around that.
Edited to reflect that I meant this meeting.
tl;dr
Let’s forbid the mix of nullish-coalescing and all operators from
**
(Exponentiation) to?:
(Conditional), aka. forcing parentheses, so we can:Basically this issue is the enhanced version of #48
Details
Why submit this issue in last minute
First I have to make apologize to the champions for submit this issue in the last minute. Though I feel current low precedence is contrary to the intuition of many programmers in the main use cases, after the last meeting, I planned to let it go, because I feel the problem can be solved by type system or linters. I didn't expect this proposal to reach stage 4 so quickly that tools (such as ESLint) don't have time to provide protection in time. And some programmers told me that TypeScript implementation was different from what I originally thought. I used to believe TypeScript would use stronger type checking for
? .
and??
, whichx
inx ?? y
must beT | null | undefined
, so it could help to exclude the bad code likea > b ?? c
that do not meet the developer's expectations (a > b
would never return nullish value). But in fact TypeScript uses a more relaxed type inference. From a type system perspective, there is nothing wrong with this choice, it just doesn't provide enough protection as I originally thought.Why high precedence may be better choice in long term
As previous discussion in https://github.com/tc39/proposal-nullish-coalescing/issues/26#issuecomment-511344028 and similar discussion in #48
a [binop] b ?? defaultValue
doesn't make sense in current low precedence becausea [binop] b
never return nullish value ([binop]
in the range from**
to|
) so?? defaultValue
is just dead code. This is why many programmers have the intuition thata > b ?? c
should behave asa > (b ?? c)
.&&
/||
and??
for ever. (Both??
and||
have low precedence, which one is lower? Programmers can never figure out that.) But high precedence could allow us finally drop the prohibition in the future. (??
have very high precedence and||
have low precedence so it's easy to say??
have higher precedence than||
)Of coz we may have disagreement of whether high precedence is really better than low precedence, and we do not have enough time in current situation before stage 4. So let's postpone it to future proposal!
Forcing parens is actually a good solution for programmers in current situation
a [binop] b ?? defaultValue
, programmers already need parens to get what they really want:a [binop] (b ?? defaultValue)
, so forcing parens won't decrease developer experience.If the committee could adopt this solution, I'd like to write the future proposal of
??
precedence and present it in Feb 2020 meeting. Thank you.