Details
-
Bug
-
Status: Open
-
Major
-
Resolution: Unresolved
-
2.3.2
-
None
-
None
Description
I've seen in groovy the break statement with named label is only allowed inside loops, in fact executing the following snippet from groovyConsole
foo: { println "foo" break foo }
I get this output
2 compilation errors:
the break statement with named label is only allowed inside loops
at line: 5, column: 13break to missing label
at line: 5, column: 13
Bu this morning a colleague of mine discovered that if you combine old-school label definition with a break label used within two nested loops you obtain no compile/runtime errors. Instead the executed logic is not the expected one, at least not what you would expect when you write that kind of code.
It seems that the break label instruction simply breaks the innermost loop execution, continuing with the outer one (hence ignoring the label).
Follows a test based on the example took from http://docs.codehaus.org/display/GROOVY/JN2535-Control:
Its output shows how the labeled code block is re-executed after the break
def i=0, j=0 outer: { println "executing outer block" while( i<5 ){ //labelling a while loop is especially useful... j= 0 i++ println "executing outer while, i: $i, j: $j" while( j<5 ){ j++ println "executing inner while, i: $i, j: $j" if( i==3 && j==2 ) break outer //...because we can break out of a specified labelled while loop } } } assert i==3 && j==2
This is its execution output:
executing outer block
executing outer while, i: 1, j: 0
executing inner while, i: 1, j: 1
executing inner while, i: 1, j: 2
executing inner while, i: 1, j: 3
executing inner while, i: 1, j: 4
executing inner while, i: 1, j: 5
executing outer while, i: 2, j: 0
executing inner while, i: 2, j: 1
executing inner while, i: 2, j: 2
executing inner while, i: 2, j: 3
executing inner while, i: 2, j: 4
executing inner while, i: 2, j: 5
executing outer while, i: 3, j: 0
executing inner while, i: 3, j: 1
executing inner while, i: 3, j: 2
executing outer while, i: 4, j: 0
executing inner while, i: 4, j: 1
executing inner while, i: 4, j: 2
executing inner while, i: 4, j: 3
executing inner while, i: 4, j: 4
executing inner while, i: 4, j: 5
executing outer while, i: 5, j: 0
executing inner while, i: 5, j: 1
executing inner while, i: 5, j: 2
executing inner while, i: 5, j: 3
executing inner while, i: 5, j: 4
executing inner while, i: 5, j: 5
Exception in thread "main" Assertion failed:assert i==3 && j==2
5| false
falseat org.codehaus.groovy.runtime.InvokerHelper.assertFailed(InvokerHelper.java:398)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.assertFailed(ScriptBytecodeAdapter.java:646)
at Bar.main(Bar.groovy:27)
Follows the java counterpart, whose output shows how the labeled code block is not executed after the break
public class Foo { public static void main(String[] args) { int i = 0, j = 0; outer: { println("executing outer block"); while (i < 5) { // labelling a while loop is especially useful... j = 0; i++; println("executing outer while, i: " + i + ", j: " + j); while (j < 5) { j++; println("executing inner while, i: " + i + ", j: " + j); if (i == 3 && j == 2) break outer; // ...because we can break out of a specified labelled while loop } } } assert i == 3 && j == 2; } static void println(String s) { System.out.println(s); } }
And this is its execution output
executing outer block
executing outer while, i: 1, j: 0
executing inner while, i: 1, j: 1
executing inner while, i: 1, j: 2
executing inner while, i: 1, j: 3
executing inner while, i: 1, j: 4
executing inner while, i: 1, j: 5
executing outer while, i: 2, j: 0
executing inner while, i: 2, j: 1
executing inner while, i: 2, j: 2
executing inner while, i: 2, j: 3
executing inner while, i: 2, j: 4
executing inner while, i: 2, j: 5
executing outer while, i: 3, j: 0
executing inner while, i: 3, j: 1
executing inner while, i: 3, j: 2
(even running it with assertions enabled through the -ea switch)