Also an interesting case: var yield = 5; var res = switch(yield) { default -> yield + yield; } // are we returning result of binary plus (10) or yielding result of unary plus (5)? Seems the first one, yet confusing.
Tagir. On Fri, May 24, 2019 at 4:30 AM Dan Smith <daniel.sm...@oracle.com> wrote: > > > On May 22, 2019, at 9:45 AM, Brian Goetz <brian.go...@oracle.com> wrote: > > > > The “compromise” strategy is like the smart strategy, except that it trades > > fixed lookahead for missing a few more method invocation cases. Here, we > > look at the tokens that follow the identifier yield, and use those to > > determine whether to classify yield as a keyword or identifier. (We’d > > choose identifier if it is an assignment op (=, +=, etc), left-bracket, > > dot, and a few others, plus a few two-token sequences (e.g., ++ and then > > semicolon), which is lookahead(2). > > > The compromise strategy misses some cases we could parse unambiguously, but > > also offers a simpler user model: always qualify invocations of methods > > called yield when used as expression statements. And it offers the better > > lookup behavior, which will make life easier for IDEs. > > There's still some space for different design choices within the compromise > strategy: what happens to names in contexts *other than* the start of a > statement? > > I think it's really helpful to split the question into three parts: variable > names, type names, and method names. > > 1) Variable names: we've established that, with a fixed lookahead, every > legal use of the variable name 'yield' can be properly interpreted. Great. > > 2) Type names: 'yield' might be used as the name of a class, type of a method > parameter, type of a field, array component type, type of a 'final' local > variable etc. Or we can prohibit it entirely as a type name. > > We went through this when designing 'var', and settled on the more > restrictive position: you can't declare classes/interfaces/type vars or make > reference to types with name 'var', regardless of context. That way, there's > no risk of confusion between subtly different programs—wherever you see 'var' > used as a type, you know it can only mean the keyword. > > I think it's best to treat 'yield' like 'var' in this case. > > 3) Method names: 'yield(' at the start of a statement means YieldStatement, > but what about other contexts in which method invocations can appear? > > Example: > var v = switch (x) { > case 1 -> yield(x); // method call? > default -> { yield(x); } // no-op, produces x (oops!) > }; > > Fortunately, the different normal-completion behavior of a method call and a > yield statement will probably catch most errors of this form—when I type the > braces above, I'll probably also try adding a statement after the attempted > 'yield' call, and the compiler will complain that the statement is > unreachable. But it's all very subtle (not to mention painful for IDEs). > > Taking inspiration from the treatment of type names, my preference here is to > make a blanket restriction that's easy to visualize: an *unqualified* method > invocation must not use the name 'yield'. Context is irrelevant. The > workaround is always to add a qualifier. > > (If, in the future, we introduce local methods or something similar that > can't be qualified, we should not allow such methods to be named 'yield'.) > > --- > > Are people generally good with my preferred restrictions, or do you think > it's better to be more permissive? >