[ 
https://issues.apache.org/jira/browse/GROOVY-11818?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Eric Milles updated GROOVY-11818:
---------------------------------
    Language: groovy

> 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: 3.0.25, 4.0.29
>            Reporter: James Daugherty
>            Priority: Minor
>
> 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