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

Broad inclusion of operators #4

Closed
littledan opened this issue Jun 6, 2017 · 20 comments
Closed

Broad inclusion of operators #4

littledan opened this issue Jun 6, 2017 · 20 comments

Comments

@littledan
Copy link
Member

This proposal includes not just ?. but also ?.[ and ?.(. It's easy to see why ?. is useful when navigating around a JSON document, and ?.[ may be for analogous situations, but the method call and constructor parts are a bit more obscure. Are these included out of an abstract sense of orthogonality, or were there particular use cases in mind that motivated them? If so, it would be good to include them in the explainer. IIRC the number of operators here was brought up at the January 2017 TC39 meeting as a point to revisit with an eye towards starting more minimally. cc @dherman

@claudepache
Copy link
Collaborator

Below are some food for thought. I may find more use cases.

(1) Given an iterator iter, you could close it manually with:

iter.return?.()

(2) Given a DOM element foo, you could run manually its eventual DOM0-onclick handler with:

foo.onclick?.()

(3) More concretely, I’ve recently encountered a situation where I wanted to run the reportValidity method of an HTML form, but fall back to skip the check for browsers which don’t implement that method (since there is of course another check server-side):

if (myForm.checkValidity && !myForm.checkValidity()) {
    // validity check has failed and errors are reported to the user
    // stop processing the form
    return;
}

With ?.(, I could have written:

if (myForm.checkValidity?.() === false) {
    // validity check has failed and errors are reported to the user
    // stop processing the form
    return;
}

because myForm.checkValidity?.() will evaluate to true or false for browsers that implement it, and undefined for those that don’t implement it yet.

@littledan
Copy link
Member Author

Those all make sense to me. Did you have anything in mind for the constructor case?

@claudepache
Copy link
Collaborator

For the constructor case, no, I’ve currently nothing in mind except completeness.

@claudepache
Copy link
Collaborator

If we want to be super complete, besides the “optional constructor” case new a?.(x), there is also the obscure “optional tagged template” case a?.`{x}`. For those two forms, in absence of compelling use cases, I don’t care.

@littledan
Copy link
Member Author

Seems like there are two decisions: which forms to include for .? versions, and which forms to short circuit over, even in the ordinary version. Would it make sense to choose the same set of forms for both of these?

@claudepache
Copy link
Collaborator

Seems like there are two decisions: which forms to include for .? versions, and which forms to short circuit over, even in the ordinary version. Would it make sense to choose the same set of forms for both of these?

For me, it would make sense that the first set is included in the second set.

@littledan
Copy link
Member Author

littledan commented Jul 21, 2017

@claudepache Yes, I agree about the subset relationship; I'm suggesting that maybe they should be equal (regardless of how expansive or restrictive we make things). The idea would be that it's less to learn.

For reference, these sets are not equal in C#--the only forms are ?. and ?[, but then short-circuiting happens over ?( as well. However, there is the subset relationship that Claude mentioned above.

@claudepache
Copy link
Collaborator

@littledan No, I don’t think that making the two sets equal make it less to learn, because it is not a useful rule. For instance, does it say whether super?.foo is allowed? (BTW, it is not. Still an obscure case that I didn’t try to spec.) Personally, I can’t even answer.

@littledan
Copy link
Member Author

OK, this seems reasonable. super?.foo does seem pretty obscure and useless, for one. Should we leave out new and templates, if utility is a thing we're thinking about here, and we haven't thought of use cases for them yet?

@claudepache
Copy link
Collaborator

claudepache commented Jul 25, 2017

I think that new (and templates) should be dropped in absence of use case. (In CoffeeScript, “soaked new” is implemented but unused in practice per #17.)

@claudepache
Copy link
Collaborator

@claudepache

No, I don’t think that making the two sets equal make it less to learn, because it is not a useful rule. For instance, does it say whether super?.foo is allowed? (BTW, it is not. Still an obscure case that I didn’t try to spec.) Personally, I can’t even answer.

I disagree with my past self. For someone not versed in the spec details, it would seem like an arbitrary restriction or an inconsistency if some construct is allowed in some location of an optional chain, but not in another. The case of super is a red herring, because it is a special feature for which it does not make much sense to be considered as ”optional”.

@littledan
Copy link
Member Author

I don't see how we can make everything work with optional chaining. It really seems like, at some point, programmers will just have to learn which things it works with, rather than taking it as an orthogonal primitive.

@rattrayalex
Copy link

programmers will just have to learn which things it works with

Why? I personally would strongly prefer to work with engineers who take the time to learn their tools, but I can certainly imagine someone just getting started with programming writing code like:

class Foo {
foo(){super??.foo()} // silence TypeError: (intermediate value).foo is not a function
}
const Bar=  {};
new Bar??.('bar' ) // silence TypeError: Bar is not a constructor

while they still have no idea what's going on to silence some errors while focusing on others. Of course, it's a pedagogical question whether they should learn that way, and many CS professors might argue that only code that passes a compiler, typechecker, linter, etc should ever be run.
However, other instructors might argue that it can be more helpful to run broken code and debug one thing at a time.

I don't think TC39 should make that pedagogical decision for the community, personally.

...Actually, to be honest, I myself might write code like that while debugging. I'd never ship it, but it might be nice to be able to eg; silence the errors while iterating on some other part of a program (eg; going back and forth between Bar being a struct or a class, deciding whether Foo should extend some other class, etc).

FWIW, the debugging explanation might also explain why we don't see this code in practice; it may have been written, but thankfully it never shipped.

@rattrayalex
Copy link

(I do recognize that there's a cost to implementing features like these, and I don't mean to claim that the benefits I stated, or others I haven't thought of, outweigh those costs).

@littledan
Copy link
Member Author

littledan commented Mar 15, 2018

There are other cases which were brought up on this repository, such as [...?x]. What if someone thinks that they can do ?x to get the variable x if it's defined, and undefined rather than a ReferenceError? Or how about x ?+ y, which will be undefined if x is null or undefined, rather than NaN? Ultimately, your imagination is the limit, and we can't include the union of everyone's imagination; we just have to make a decision at some point about what's in scope for this proposal.

@claudepache
Copy link
Collaborator

claudepache commented Mar 15, 2018

@rattrayalex

foo(){super??.foo()} // silence TypeError: (intermediate value).foo is not a function

I have no intention of making super??.foo() produce anything else than a syntax error.

const Bar=  {};
new Bar??.('bar' )  // silence TypeError: Bar is not a constructor

I am reluctant to make new Bar??('bar' ) work, because of the technical difficulty to write the grammar. You need a solid use case.

@rattrayalex
Copy link

There are other cases which were brought up on this repository ...

I think the difference with these is that they "look just like" member chaining and function soaking. That is, a naive writer of JavaScript would expect these to work (eg; they are not aware that super is a special token), but might be unsure as to whether ??+ or ...??x would work.

because of the technical difficulty to write the grammar

Fair enough 😄

I have no intention to make super??.foo() to produce anything else than a syntax error.

That doesn't sound unreasonable to me, but I'm actually curious why?

@claudepache
Copy link
Collaborator

claudepache commented Mar 15, 2018

I have no intention to make super?.foo() to produce anything else than a syntax error.

That doesn't sound unreasonable to me, but I'm actually curious why?

Because I don’t know how to make sense of it, and I am unwilling to think of the most reasonable meaning just for the sake of it. And even if I determined the meaning it should have, I am unwilling to introduce it in the spec just because it looks nice to have ?. for everything that resembles vaguely to a property access.

But if you have reasonable meaning and a reasonable use case, just open an issue.

@claudepache
Copy link
Collaborator

For reference, other issues about in/ex-cluding operators from optional chains:

Currently included in the spec:

Currently excluded from the spec:

sendilkumarn pushed a commit to sendilkumarn/proposal-optional-chaining that referenced this issue Jun 22, 2019
@claudepache
Copy link
Collaborator

Now that we are at Stage 3, we can consider that the set of included operators is fixed. There remains only the relatively minor issue of private field access: see #28.

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

No branches or pull requests

3 participants