-
Notifications
You must be signed in to change notification settings - Fork 27
Which token is best for lexical declarations in a class declaration? #9
Comments
inner could get confusing with nested class definitions. |
|
I like |
Is scope less technical than lexical? |
@ljharb, what's the confusion with |
I can still barely tell you what it means. I’ve at least heard of function scope, though, and curly-brace scope with |
|
@bakkot basically, which inner is it referring to? Indeed it’d be lexical, so it’d be everything that’s nested lexically inside the class (ᕕ( ᐛ )ᕗ) but I’m not sure how clear that word makes it. |
This patch specifies lexically scoped declarations in class bodies, with a token preceding them. Because we haven't figured out which token to use (#9), <placeholder> is used instead. Some main design points: - let, const, class and function (including async fns, generators) are supported, and var declarations are not supported. - Function declarations are hoisted to the top of the block, before evaluating the extends clause. - let, const and class declarations are evaluated interspersed with static public field initializers. - The class is visible with a binding initialized when the lexical declarations are evaluated. - Unlike static public field initializers which are in a scope analogous to a method (with super property access, and this being the class), the scope of lexical declarations inherits directly from the outer scope, similarly to computed proerty names and the extends clause, which implies: - this, super, new.target are inherited from the lexical context, and are not related to the current class definition. - arguments is not poisoned and is inherited from an outer definition - yield, await can be used if possible in the enclosing function.
This patch specifies lexically scoped declarations in class bodies, with a token preceding them. Because we haven't figured out which token to use (#9), <placeholder> is used instead. Some main design points: - let, const, class and function (including async fns, generators) are supported, and var declarations are not supported. - Function declarations are hoisted to the top of the block, before evaluating the extends clause. - let, const and class declarations are evaluated interspersed with static public field initializers. - The class is visible with a binding initialized when the lexical declarations are evaluated. - Unlike static public field initializers which are in a scope analogous to a method (with super property access, and this being the class), the scope of lexical declarations inherits directly from the outer scope, similarly to computed proerty names and the extends clause, which implies: - this, super, new.target are inherited from the lexical context, and are not related to the current class definition. - arguments is not poisoned and is inherited from an outer definition - yield, await can be used if possible in the enclosing function.
I'd like to choose a token to be a concrete strawman (cf #14). How about |
|
Please keep bikeshedding here too everyone! |
I still prefer no leading token. With People, presumably lean about blocks and lexical scope early in the process of learning modern JS. These proposed class body lexical declarations have a meaning that is already consistent with what they have already leaned -- they are scoped to the enclosing { } scope, which just happens to be a class body. Once they learn that class bodies allow lexical declarations (distinct from fields) the prefix token is just noise. |
@allenwb We've heard people express reservations about both no leading token and |
Well, and I've expressed reservations about having such a token. 😀 I'd suggest getting input from people that may have strong options about consistency of lexical declarations and scopes. Maybe: Mark Miller, Dave Herman, Brendan, Sam T-H, etc. I think I would be content with only having |
Thanks @allenwb . My ranking of choices:
Choices I consider disqualified:
The I initially liked |
I would think that if we allowed nested class definition we could make it a special case that doesn't have the repeated class prefix (after all, it's really just a noise word). However, I'm not sure that nested classes can work because of staging issues WRT evaluation order of class member elements. Would need to work out details to be sure. |
Parts of a relevant conversation with @getify: Getify:
|
@allenwb Ah, reminds me of Paris in the spring... (Those There's a minor technical issue with using bare
I suppose we'll need a couple of tokens of lookahead to disambiguate async methods from an async function declaration. Is that a problem? |
@zenparsing is it not just |
I brought this up long ago and suggest we ban unquote |
@allenwb @getify I agree about consistency. However, it seems to me that both generality and consistency argue that we do not make a special case for lexical function declarations, as opposed to lexical declarations in general --- including @allenwb I am curious if there is a lurking need to treat nested classes specially. I understand the issue --- that classes have initialization phases, including evaluating expressions (superclass and computed properties). But I don't see any reason why this should cause nested classes to need special handling. If nested classes do not otherwise need to be a special case, then we should not make a special syntactic case for them merely to avoid the text |
@erights I'm find with (for consistency) including all of those without a special token. But if the choice was only function without a special token or all of them with a special token, I'd go with the only function option. Basically if class bodies are super special then we are justified in only allowing Regarding nest classes. I'm concern about things like: class C {
class N extends C { /* stuff that depends upon C being following defined */}
} But I guess it isn't any worse than: class C {
constructor() {
/* stuff that expects C to be fully defined */
}
static x = new C
} In either cases the code will probably error out at runtime. |
At the January 2018 TC39 meeting, @waldemarhorwat expressed strong skepticism for including any sort of token here. From Waldemar's point of view, I believe, a token would be meaningless noise and add something additional to remember. On the other hand, many others have expressed concern that bare function declarations in class bodies would be confusing. I'm not sure how to find a good, widely agreeable solution here. |
The current Stage 3 proposal includes only static class features, and no lexical declarations. |
As @ljharb suggested in #4 (comment) , we may want to use a token to set off lexically scoped function and variable declarations in class bodies.
What would be a good value for
<placeholder>
? We could use basically whatever we want here, as long as we're ok with a no-newline restriction between the token and the following lexical declaration. Some candidates:static
(from @ljharb)class
(from @allenwb)inner
(from @bakkot)local
(from @bakkot)shared
(from @erights)scoped
(from @jridgewell)nested
(from @domenic)lexical
(new here)What do you think about these? In #4, some disadvantages of
static
andclass
have been mentioned. As an initial strawperson, what if we go withinner
?The text was updated successfully, but these errors were encountered: