-
Notifications
You must be signed in to change notification settings - Fork 75
(a?.b).c #33
Comments
Option 1 makes sense to me, but having added parens change the meaning seems weird. |
I still don't see why parenthesis should change the meaning of simple property access: const a = null;
(a?.b).c // Throws, per Option I
// Why not just write?
a.b.c // Throws |
that's also a really good point. |
The current state of the spec incidentally* opt for option I, because it is based on syntax only, and in general, parts of a non-separable construct cannot be arbitrary “split” with parentheses. I’m thinking in particular of destructuring assignment: ({x: y}) = b // ReferenceError, because the LHS is interpreted as a plain object literal. That is distinct from, e.g., (*) I say “incidentally”, because (concerning optional chaining) this is an edge case that has zero practical use (whatever option we choose), if you think two seconds about it. |
So, seems like there is mostly consensus on Option I? If so, maybe we can (a) close this issue and (b) clarify in the proposal (specifically, maybe remove this section?) that there isn't anything magical about wrapping things with ()s (and point to this thread here in case anyone wants to see the historical discussion on it)? |
FWIW C#, Swift, and Coffeescript also have the semantics of Option I: C# (playground) class A { public B b; };
class B { public int c; };
A a = null;
int? x;
x = a?.b.c; // null
x = (a?.b).c; // throws Swift (playground) class A { var b: B? }
class B { var c: Int = 0 }
let a: A? = nil
var x: Int?
x = a?.b!.c // nil
x = (a?.b)!.c // throws Coffeescript (playground) a = null
x = a?.b.c # undefined
x = (a?.b).c # throws |
Optional-chained member access should probably have the same operator precedence as other types of member access (19), lower than grouping/parentheses (20): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence So this would correspond exactly to Option 1, which seems to be the consensus anyways. Looking forward to seeing this happen! |
We previously discussed this issue in #20 . As a result of that thread, we switched from option II to option I. @jridgewell Are you convinced by the reasons @claudepache has given here and the discussion in the previous thread? Personally, I find option I more intuitive because you have an easy syntactic way to see the exact scope of short-circuiting. |
Option 1 works for me. |
What I find difficult about Option 1 is that in |
Also, I don't think operator precedence is relevant for this question (unlike @bpartridge suggested). Under both options, parsing is the same, it's just behavior that differs, just as a function body doesn't end at an early |
I agree, parentheses shouldn't have any extra special meaning there Equivalent expressions (a?.b).c
a?.b.c
(a == null ? undefined : a.b).c edit: they are not fully equivalent #69 (comment) Those are equivalent too: (a?.b ?? {}).c // (using null coalescing operator, stage 3)
((a == null ? undefined : a.b) ?? {}).c
(a == null ? {} : a.b == null ? {} : a.b).c
a == null ? undefined : a.b == null ? undefined : a.b.c And those (a?.b)?.c
a?.b?.c
a == null ? undefined : a.b == null ? undefined : a.b.c |
Parentheses don’t have extra special meaning, but But this is not something you need to worry about, as you won’t write |
This is an open discussion point in the explainer, moving it into an issue to allow us to have a discussion, form an opinion and propagate the resolution back to the explainer.
Should parentheses limit the scope of short-circuting?
A really neat property of
option I
is that it follows along the very simple de-sugaring ofa == null ? undefined : a.b
.Can you help me understand what kinds of benefits/use cases one would capture with option II that justifies it breaking the simplicity/consistency of the de-sugaring?
The text was updated successfully, but these errors were encountered: