Skip to content

Special casing class/function declarations to have completion semantics #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
clemmy opened this issue Nov 17, 2017 · 3 comments
Open

Comments

@clemmy
Copy link

clemmy commented Nov 17, 2017

The completion value of class and function declarations are undefined.

eval('class x {}') // undefined
eval('(class x {})') // class x{}
eval('function x() {}') // undefined
eval('(function x(){})') // function x() {}
eval('() => {}') // () => {}

From my understanding, there hasn't been much of a use case for completion values of class and function declarations in the past, but it can be a valid use case as do-expressions become more popular. Consider the following JSX:

<div onClick={do {
  if (flag) {
    function a() {...}
  } else {
    function b() {...}
  }
}} />

In the above example, the onClick handler will be assigned a value of undefined, which is probably not what the user would intend from writing the code.

Is there a way to special case these so that they have completion semantics?
e.g.

eval('class x {}') // class x{}
eval('function x() {}') // function x() {}

There may also be other such declarations with similar concerns.

@claudepache
Copy link

Trying to disguise function declarations into expressions raises some issues, however.

  1. The completion value of declarations (and empty statements) is not exactly undefined, but empty, meaning that the completion value of the preceding statement is forwarded. For example:
"use strict";
(do {
    if (true) {
        let x = 4;
        y = f(x);
        y + 2;
        function f(x) {
            return x*10;
        }
    }
})

As currently specced, the do-expression evaluates to 42, despite the function declaration. Until proof of the contrary, this is what the programmer intended.

  1. In your example, people will try to write:
(do {
  if (flag) {
    function () {...};
  } else {
    function () {...};
  }
})

but this is a syntax error, as the function keyword at the beginning of the statement is always interpreted as starting a function declaration, and function declarations must be named. That said, we could allow unnamed function declaration just for the sake of this case.

@pitaj
Copy link

pitaj commented Dec 3, 2017

I think it would be better to just outright ban function declarations from do expressions, instead treating every function keyword as the start of a function expression. Odds are, people using do expressions are fine with using arrow function for everything, or otherwise using function expressions for the rare case that they need a different this context.

Another option is treating function declarations by different semantics in do expressions, removing block hoisting and treating function declarations as expressions as well. (Essentially the same behavior as let functionName = function functionName() {}).

As for class, the two declarations would have to have identical semantic shifts in do expressions. I prefer outright banning both.

@bakkot
Copy link
Collaborator

bakkot commented Jan 30, 2021

The current proposal bans all declarations, including function and class, at the end of do expressions. That prevents the confusion from arising, but is kind of awkward. I'd be interested in seeing if we can change the completion values for declarations in general, although not necessarily as part of this proposal.

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

No branches or pull requests

4 participants