[ 
https://issues.apache.org/jira/browse/GROOVY-11744?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18133978#comment-18133978
 ] 

ASF GitHub Bot commented on GROOVY-11744:
-----------------------------------------

paulk-asert commented on PR #3073:
URL: https://github.com/apache/groovy/pull/3073#issuecomment-6488309928

   Thanks Daniel. While reviewing this I found that the 5.x behaviour I 
described in the JIRA (`def (_, y, _) = [3, 4, 5]; println _` printing 5 in 
dynamic code) already changed in **6.0.0**, before this PR. I'm not sure that 
was intended: it came from a4d584762f (GROOVY-12242, pattern-variable scoping). 
A variable that is not declared in scope now always resolves as a property, 
even when a local of that name exists. Repeated `_` has never been declared for 
scoping, so every read of it became a property lookup. That change wasn't 
announced in COMPATIBILITY.md either. This PR keeps that behaviour and adds a 
test that asserts it.
   
   Since we're keeping single `_` as a valid identifier, I'd rather not make 
repeated `_` a different kind of thing. Developers shouldn't have to think 
about single-assignment and multi-assignment differently, and Java doesn't have 
multi-assignment, so it doesn't settle this for us. I've put up #3075 as an 
alternative: `_` is always an ordinary variable that may be declared again, 
each declaration replacing the earlier `_`. It's a ~10-line change in 
`VariableScopeVisitor` and needs no classgen changes. It also flips the three 
GROOVY-10943 STC "undeclared" tests and adds a 6.0.1 COMPATIBILITY entry. Could 
you take a look and see which you prefer?
   
   ### The rule developers need to know
   
   | Version | Rule |
   |---|---|
   | 5.1.3 | A single `_` is an ordinary variable. A `_` repeated in one 
declaration or parameter list is not declared, but its values are still stored. 
Dynamic code reads the last value, while STC/SC reports it as undeclared and 
closures can't see it. Redeclaring `_` is the usual duplicate error, except 
that a repeated-`_` declaration silently overwrites an existing `_`. |
   | 6.0.0 | As 5.1.3, except that reading `_` after a repeated `_` is a 
property lookup (binding, field or `MissingPropertyException`). The values are 
still stored, so an existing local `_` is still overwritten. |
   | #3073 | A repeated `_` is unnamed: it declares and stores nothing. Reading 
`_` afterwards finds the `_` that existed before (local, field or binding) or 
fails. A single `_` in a tuple is an ordinary variable and is checked for 
duplicates. |
   | #3075 | `_` is an ordinary variable that may be declared again. Each 
declaration (single, repeated, tuple, parameter or `catch`) replaces the 
earlier `_`, so you see the last value. Other names, and method/constructor 
parameters, are still checked for duplicates. |
   
   ### Behaviour
   
   | # | Code | 5.1.3 | 6.0.0 | #3073 | #3075 |
   |---|---|---|---|---|---|
   | 1 | `def (_, y, _) = [3, 4, 5]; _` | 5 | MPE | MPE | 5 |
   | 2 | `def c = { _, _ -> _ }; c(2, 3)` | 3 | MPE | MPE | 3 |
   | 3 | binding `_ = 'b'`; `def (_, y, _) = [3, 4, 5]; _` | 5 | `'b'` | `'b'` 
| 5 |
   | 4 | `def _ = 1; def (_, _) = [2, 3]; _` (the ticket) | 3 | 3 | 1 | 3 |
   | 5 | `def _ = 1; def x = (_, _) -> _; x(2, 3)` (the ticket) | 3 | 3 | 1 | 3 
|
   | 6 | `def (_, y, _) = [3, 4, 5]; def (_, z, _) = [6, 7, 8]; _` | 8 | MPE | 
MPE | 8 |
   | 7 | `def (_, y, _) = …; def (_, z) = [6, 7]; def (_, w, _) = [8, 9, 10]; 
_` | 10 | 10 | 6 | 10 |
   | 8 | `def (_, y) = [1, 2]; def (_, z, _) = [3, 4, 5]; _` | 5 | 5 | 1 | 5 |
   | 9 | `def (_, y) = [1, 2]; def (_, z) = [3, 4]; _` | error | error | error 
| 3 |
   | 10 | `def _ = 1; def _ = 2; _` | error | error | error | 2 |
   | 11 | `def _ = 1; [10].each { _ -> … }; _` | error | error | error | 1 
(closure parameter shadows `_`) |
   | 12 | `def (_, y, _) = [3, 4, 5]; def c = { _ }; c()` | MPE | MPE | MPE | 5 
|
   | 13 | `@CompileStatic`: `def (_, y, _) = [3, 4, 5]; _` | STC error | STC 
error | STC error | 5 |
   | 14 | `@CompileStatic`: `def (int _, String s, String _) = [1, 'a', 'bc']; 
_.length()` | STC error | STC error | STC error | 2 |
   | 15 | `@CompileStatic`: `def _ = 1; def (_, y, _) = [3, 4, 5]; _` | 5 | 5 | 
1 | 5 |
   | 16 | `def (x, _, y, _, z) = [1, 2, 3, 4, 5]` (named slots) | 1 3 5 | 1 3 5 
| 1 3 5 | 1 3 5 |
   | 17 | `(_, y, _) = [3, 4, 5]` (assignment, no `def`) | 5 | 5 | 5 | 5 |
   | 18 | `def x = 1; def x = 2` / `def m(_, _) {}` | error | error | error | 
error |
   
   MPE = `MissingPropertyException`; "error" = "The current scope already 
contains a variable of the name …".
   
   A few observations:
   - Rows 1–3, 6 and 12 are the 6.0.0 regression. #3075 restores 5.x for them, 
and also makes row 12 work, which no version did before.
   - #3073 makes rows 7 and 8 depend on whether an earlier tuple had one `_` or 
two. With #3075, every row follows from the single rule above.
   - #3075 does keep 5.x's answer for the ticket's own case (rows 4/5: `_` is 
the last value). That's consistent with "declaring `_` again replaces it" and 
is documented as such. Java also allows `var _ = a(); var _ = b();`, so 
declaring `_` again is closer to Java than today's error.
   - Bytecode: in every version, each `_` declaration already gets its own 
local slot, and the ranges in the local variable table don't overlap. A 
debugger therefore shows one `_`, the latest one. #3075 doesn't change classgen 
at all.




> Unnamed variables are actually used
> -----------------------------------
>
>                 Key: GROOVY-11744
>                 URL: https://issues.apache.org/jira/browse/GROOVY-11744
>             Project: Groovy
>          Issue Type: Bug
>            Reporter: Georgii Ustinov
>            Assignee: Daniel Sun
>            Priority: Major
>
> I am currently implementing Groovy 5 support inside Intellij IDEA and 
> encountered the following behaviour. Consider the following code:
> {code:java}
> package org.example.demo
> static void main(String[] args) {
>     def _ = 1
>     def (_, _) = [2, 3]
>     println _
> } {code}
> I expected that it will print 1, since variable declaration contains only 
> unnamed variables.
> Actually it prints 3. The same behaviour can be encountered here:
> {code:java}
> def _ = 1
> def x = (_, _) -> {
> println(_)
> }
> x(2, 3){code}
> I beileve this is a bug. 



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to