Groovy 6, switch re-classification results in expr...
# groovy
j
Groovy 6, switch re-classification results in expression switches being classified as statements. What is the intended behaviour of yield inside an arrow style switch statement in groovy 6? Should yield be rejected at compile time or supported with early exit semantics? The current 6.0 behaviour seems buggy to me: https://groovyconsole.dev/?g=groovy_6_0&codez=eNpLSU1TKMhMztZIys_PSU3MU0jLSUzXVKjmUgCC4vLMkuQMBQ1DmAAIJCcWpyoYKujaIYmBQGaaggZEc2Vmak6KgnpaZlFxiTqKGqhMcWpyfl4KQqqWC0LWcnElFhenFpVAnFRSVJqqqWBrCzMKAGONLXI#4pwF8p6YI5
v
Hm, also the error message seems buggy to me. If you replace
yield
by
return
it says
switch expression does not support
return
While it should be something like
arrow-style switch does not support
return
Now that not every arrow-style switch is an expression.
Hm, no, the docs also say that with colon-style switch you have to use
yield
if used as expression, so it is not bound to arrow-style but should indeed be bound to being an expression or not. So I guess it should indeed complain about
yield
being used when arrow-style switch is used as statement and allow
return
instead, which then should probably also the behavior you mentioned.
j
Supporting early exit with yield in arrow switch statements would keep them backwards compatible with groovy5 switch expressions, at least for this case
s
Very much looks like a bug unless i'm missing something here. The same switch behaves differently if it is part of a function gwc-experiment.appspot.com/?g=groovy_6_0&codez=…
v
As I said, yes, i think it is a bug. This is not about "inside a function" but about "used as an expression". Even your usage in the function does not count as expression, but as statement and the usual last-statement of the function defines return value kicks in. If you add a
return
in front of the
switch
, it is an expression and behaves like expected. I still think the bug is, that the switch-statement in arrow-shape is considered an expression when it actually is a statement. It should complain that there is
yield
and instead allow and require
return
and would then also behave as expected.
p
Good catch — that's a regression, not intended. In 5.1.2 and 6.0.0-RC-1 your snippet gives 'first'; from RC-3 (incl. 6.0.0) it gives 'second'. When a trailing switch became a statement (GROOVY-12408), the parser started lowering
yield x
to a plain expression, so a non-final yield is silently a no-op and execution falls through. The same lowering also affects value-discarded switches, and
yield
inside a loop within an arm now fails to compile. Intended behaviour is that it's supported with early-exit semantics: the reclassification was only meant to change the encoding, and 4.x/5.x code had to use
yield
in block arms, so rejecting it would break working code. In return position yield should behave like
return
, otherwise like a
break
out of the switch. We'll raise a JIRA and target 6.0.1. Workaround meanwhile: write
return switch (...) { ... }
(keeps it a switch expression), or restructure the arm so the only yield is the last statement (if/else with a yield in each branch).
👍 1
v
Nevertheless, the error message is also wrong, isn't it? I mean if you place
return
instead of yield and it says that in switch expression
return
is not supported. I learned that now with 6, it is not a switch expression just because it has arrow-shape. So I wonder, why does it tell about switch expression when it is a switch statement and also why is
return
not supported if it is now a switch statement. 😦
p
The GEP-19 PR (Groovy 7) has the return/break/continue fix 42d5425cb7. I'll backport that to Groovy 6. The error dates back to when all bodies were closures, so return would have been return from the closure.