Skip to content
This repository has been archived by the owner on Jan 25, 2022. It is now read-only.

Add FAQ explaining optional call semantics. #93

Merged
merged 6 commits into from
Jun 25, 2019
Merged

Add FAQ explaining optional call semantics. #93

merged 6 commits into from
Jun 25, 2019

Conversation

rkirsling
Copy link
Member

@claudepache
Copy link
Collaborator

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... 😛)

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Jun 21, 2019

Optional chaining is not an error-suppression mechanism

Yup, I think that is worth specifically calling out in the FAQ in this section.

@rkirsling
Copy link
Member Author

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.

Good point! I added a link from one FAQ item to the other. 👍

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... 😛)

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.

@claudepache
Copy link
Collaborator

claudepache commented Jun 21, 2019

Please do push back if there's anything you don't like... 😅 The cleanup here was intended to be mostly mechanical, after all.

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?)

@ljharb
Copy link
Member

ljharb commented Jun 21, 2019

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!

Copy link
Member

@littledan littledan left a 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.
Copy link
Member

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).

Copy link
Member Author

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.
Copy link
Contributor

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., if this.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 😄

Copy link
Member Author

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. 😄

Copy link
Contributor

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.

Copy link
Collaborator

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.

Copy link
Member Author

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.

Copy link
Collaborator

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.

Copy link
Member

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.

@rkirsling
Copy link
Member Author

rkirsling commented Jun 24, 2019

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.

@jridgewell
Copy link
Member

I have no preference, let's merge.

Copy link
Member

@littledan littledan left a 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.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants