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

Paul King commented on GROOVY-11744:
------------------------------------

This is fixed on master (Groovy 7) and on GROOVY_6_0_X for 6.0.1. Here is a 
summary of the behaviour, so you don't need to piece it together from the 
commits.

h3. Rule

A variable named \{{_}} may be declared again in the same scope or in an 
enclosing scope. Each declaration is a new variable, and it replaces the 
earlier \{{_}} for everything that follows it. That's all there is to it: a 
repeated \{{_}} in a multi-assignment or in a closure or lambda parameter list 
is just \{{_}} declared more than once. Nothing is treated as a placeholder any 
more.

h3. What an IDE should do

*Resolution.* A reference to \{{_}} resolves to the nearest \{{_}} declaration 
before it, as with any variable:
{code:groovy}
def (_, y, _) = [3, 4, 5]
assert _ == 5                      // the last _ in the tuple

def c = \{ _, _ -> _ }
assert c(2, 3) == 3                // the last parameter
def l = (_, _) -> _
assert l(2, 3) == 3

def _ = 1
def _ = 2
assert _ == 2
{code}

*Each redeclaration is a separate variable.* Something that captured an earlier 
\{{_}} keeps it:
{code:groovy}
def (_, y) = [1, 2]
def c = \{ _ }                      // captures this _
def (_, z) = [3, 4]                // a new _
assert c() == 1
assert _ == 3
{code}

*An inner declaration shadows the outer \{{_}}; it doesn't change it.* This 
applies to closure and lambda parameters, locals in a closure, and catch 
parameters:
{code:groovy}
def _ = 1
def c = \{ def _ = 5; _ }
assert c() == 5
[10].each \{ _ -> assert _ == 10 }
try \{ throw new Exception() } catch (Exception _) \{ }
assert _ == 1
{code}

*Script binding.* A declared \{{_}} hides a \{{_}} in the script binding and 
leaves the binding's value unchanged.

h3. Errors

No longer an error: any redeclaration of a local \{{_}}:
* \{{def _ = 1}} followed by \{{def _ = 2}}
* \{{def (_, y) = …}} after an existing \{{_}}
* \{{{ _ -> … }}} or \{{catch (Exception _)}} inside the scope of a \{{_}}

Still an error ("The current scope already contains a variable of the name _"):
* duplicate method or constructor parameters, e.g. \{{def m(_, _) { }}}, 
because a JVM signature can't have two parameters with the same name
* fields and properties named \{{_}}
* duplicates of any other name

Unchanged: an undeclared multi-assignment \{{(_, y, _) = …}} assigns the 
existing \{{_}}, or the binding variable, twice.

h3. Static type checking (\{{@TypeChecked}} / \{{@CompileStatic}})

{\{_}} has the type of the declaration it resolves to, which is the last one 
before the reference:
{code:groovy}
@groovy.transform.CompileStatic
def m() {
    def (int _, String s, String _) = [1, 'a', 'bc']
    _.length()                     // _ is a String
}

@groovy.transform.CompileStatic
def n() {
    def _ = 1
    def _ = 'two'
    _.length()                     // _ is a String
}
{code}
Reading \{{_}} after a repeated \{{_}} used to give "The variable [_] is 
undeclared". It is now an ordinary read.

h3. Versions

* *6.0.1 and later, including 7:* the behaviour above.
* *6.0.0:* the regression reported here. Reading \{{_}} after a repeated \{{_}} 
threw \{{MissingPropertyException}} or found a \{{_}} in the binding.
* *5.x:* only the placeholder form is allowed: a repeated \{{_}} in a 
multi-assignment declaration or in closure/lambda parameters. Reading it under 
static type checking gives "The variable [_] is undeclared". Any other 
redeclaration of \{{_}} is an error.

h3. API

{\{org.codehaus.groovy.control.PlaceholderVisitor}} isn't used by the compiler 
any more:
* *7:* removed.
* *6.0.1:* deprecated for removal; \{{isPlaceholder()}} returns \{{false}} for 
code the compiler produced.

If you need to know whether a variable is \{{_}}, check its name. The 
COMPATIBILITY.md entries for 6.0.1 and 7 have the full notes.

> 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: Paul King
>            Priority: Major
>             Fix For: 7.0.0-alpha-1, 6.0.1
>
>
> 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