James Daugherty created GROOVY-11818:
----------------------------------------

             Summary: For loop variable reference in anonymous classes yields 
unexpected results
                 Key: GROOVY-11818
                 URL: https://issues.apache.org/jira/browse/GROOVY-11818
             Project: Groovy
          Issue Type: Bug
    Affects Versions: 4.0.29, 3.0.25
            Reporter: James Daugherty


I'm not sure if this is really a bug or design decision of Groovy that could be 
improved. 

Given this java code: 
{code:java}
import java.util.*;
import java.util.stream.*;

class MyCommand {
    String filename;
    MyCommand(String filename) { this.filename = filename; }
    String getFilename() { return filename; }
}

interface MyFile {
    String getFilename();
}

List<MyCommand> commands = List.of(
    new MyCommand("testing1"),
    new MyCommand("testing2")
);

List<MyFile> files = new ArrayList<>();

for (MyCommand cmd : commands) {
    MyFile file = new MyFile() {
        @Override
        public String getFilename() {
            return cmd.getFilename();
        }
    };    
    files.add(file);
}

List<String> filenames = files.stream()
    .map(MyFile::getFilename)
    .collect(Collectors.toList());

filenames
 {code}
You can execute this code in jshell, and it will output: 
{code:java}
|  created class MyCommand
|  created interface MyFile
commands ==> [MyCommand@34c45dca, MyCommand@52cc8049]
files ==> []
filenames ==> [testing1, testing2]
filenames ==> [testing1, testing2] {code}
But the equivalent in groovy code: 
{code:java}
class MyCommand {
    String filename
}
interface MyFile {
    String getFilename()
}
List<MyCommand> commands = [new MyCommand(filename: 'testing1'),new 
MyCommand(filename: 'testing2')]

List<MyFile> files = []
for(MyCommand cmd in commands) {
    MyFile file = new MyFile() {
        String getFilename() {
            cmd.filename
        }
    }
    files.add(file)
}
files.collect{  it.filename }{code}
will output 
{code:java}
[testing2, testing2] {code}
 in Groovy 3.0.25 & 4.0.29 (tested in GroovyConsole).  Adding a local variable 
to store the filename for that loop will fix the groovy code to return the same 
value as the Java equivalent.  It seems the `cmd` variable is being reused on 
each iteration instead of creating a new reference.  This causes code inside of 
the for loop for previous iterations to be updated to the new iteration value - 
which is inconsistent with Java's behavior.

Note: using the closure iteration syntax (.each \{ }) does not have this same 
behavior as Java.  Since both Java & the closure iteration syntax produce the 
same result, I think the for loop difference should be considered a bug in 
Groovy.

 

  

 



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to