-
Notifications
You must be signed in to change notification settings - Fork 75
Add FAQ explaining optional call semantics. #93
Conversation
Also related: Optional chaining is not an error-suppression mechanism (last item of the FAQ). That is, its purpose is to distinguish between nullish and non-nullish, not between erroneous and correct. Concretely, I’m planning to add the following example in the last item of the FAQ: true?.() // TypeError: true is not a function. (unless you decide to incorporate that change in this PR, given that you already incorporated unrelated modification of personal style choice in other FAQ items... 😛) |
Yup, I think that is worth specifically calling out in the FAQ in this section. |
Good point! I added a link from one FAQ item to the other. 👍
Please do push back if there's anything you don't like... 😅 The cleanup here was intended to be mostly mechanical, after all. Also if it's just that one line to add, you could technically incorporate it here via the GH suggestion feature! Up to you though. |
No worry, it does not make me itch when I see unnecessary </dd>/</dt>/</li>s. (Or unnecessary semicolons at the end of JS statements. BTW, I suspect that there is a strong correlation between those two style preferences?) |
Probably so, since neither are unnecessary - they’re so necessary the engine inserts them for you to attempt to correct your mistake ;-) but let’s not get into that debate here! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this clarification and markup cleanup!
README.md
Outdated
|
||
From a usage perspective, one might imagine a library which will call a handler function, e.g. `onChange`, just when the user has provided it. If the user provides the number `3` instead of a function, the library will likely want to throw and inform the user of their mistaken usage. This is exactly what the proposed semantics for `onChange?.()` achieve. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might put these two paragraphs in the other order. I don't think we have to identify one of the two as the "primary" reason--they are both valid (and I would weigh the second one higher than the first, personally).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I added a commit that reverses them; hopefully folks can chime in about which they prefer.
Either way, I agree with you that neither reason need be called "primary".
|
||
Moreover, this ensures that `?.` has a consistent meaning in all cases. Instead of making calls a special case where we check `typeof foo === 'function'`, we simply check `foo == null` across the board. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might combine this and the next sentence, into something like:
furthermore, this ensures that
?.
has consistent behavior with other cases like property access, i.e., ifthis.onChange
is not callable,this.onChange()
will throw a TypeError; this is consistent with the fact that optional chaining is not an error-suppression mechanism.
Take or leave my suggestion 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really do want the consistency argument to stand on its own though—the fact that a?.b
, a?.[b]
, and a?.(b)
all perform the same check is an important point separate from error concerns. 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sold 👍... my only concern was that people take the decision to be driven by simplicity to implement, vs., elegance; this approach feels both the simplest to implement and most elegant to me, and I'm probably overthinking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact, consistency (or, said otherwise, uniformity of treatment) was my primary reason when I wrote the spec. That is, I specced it the more regular way that provides something useful for the common case (discriminating between nullish and a value supporting the following operation, be it function call or property access). Then, I checked that it did not something too weird for the edge case (something neither nullish nor supporting the following operation).
We can find arguments both ways. For example, when I wrote the following example in the explainer:
iterator.return?.() // manually close an iterator
i was very well aware that, although the spec did internally a similar operation when closing an iterator, it checks callability rather than non-nullity. I did not even ponder about making a note about that discrepancy, because it is an edge case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@claudepache Would you rather that we put the two paragraphs back in their original order then (sans the word "primary")? I think that's the last remaining concern here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rkirsling I would personally put the two paragraphs in their original order. However, it doesn’t really matter, since both reasons are valid on their own.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bcoe Note that simplicity to implement has never been a factor in this discussion. All the alternatives we discussed for this proposal should be relatively simple to implement. The tradeoffs are all at the design level.
I suppose the usage-first arrangement might be considered more "developer-oriented" while consistency-first would be more targeted at people working directly with the spec (also perhaps the consistency argument is more obvious, hence our not having had a FAQ item for this previously?). I don't know if there's a definitive answer here, but unless @jridgewell, @DanielRosenwasser, or @dustinsavery have a strong opinion, perhaps we should just move forward with what we've got. |
I have no preference, let's merge. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to land; order is not a big deal for me.
@littledan @DanielRosenwasser @bcoe @jridgewell @dustinsavery