[
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)