Java-style for loop

Veracity

Developer
Staff member
Revision 17460 says this:

---

Add Java-style "for" loop:

for (INIT [, INIT]* ; CONDITION ; ITERATE [, ITERATE]* ) BODY

You can have 0 or more INIT statements, which can be of the form

X = EXP (where X is declared already) or
TYPE X = EXP (where X of type TYPE will be declared in the BODY scope).

You can have 0 or more ITERATE statements, which can be of the form

X++ or X--
++X or --X
X OPER EXP (where OPER can be =, +=, -=, etc.

BODY can be a single statement ending with a ; or a block enclosed in {}, with no ; at the end, just like any loop.

break, continue, return, or exit are allowed within BODY, just like any loop.

---

I just realized that I forgot to say that CONDITION is a boolean expression. I also realized that I probably did not allow you to omit it, which would default to "true". I'll fix that by and by.

I did a fair amount of whackage elsewhere in the parser - mostly adding types to various collection objects - so it is possible I broke something. Let me know ASAP if you see any issues.

And let me know if the new-style for loop works as you expect.
 

Veracity

Developer
Staff member
OK. Revision 17461 lets you omit the CONDITION.

Code:
int i = 5;

print( "test: ;;" );
for( ;; ) {
    print( "i = " + i );
    if ( --i == 0 ) {
	print( "time for a break!" );
	break;
    }
}

print( "test: ;CONDITION;" );
for ( ;i < 5; ) {
    print( "i = " + i++ );
}

print( "test: INIT;CONDITION;" );
for ( i=1 ;i < 5; ) {
    print( "i = " + i++ );
}

print( "test: INIT;CONDITION;" );
for (int j=6 ;j < 10; ) {
    print( "j = " + j++ );
}

print( "test: INIT;CONDITION;ITERATE" );
for ( int j=12 ; j < 18 ; j++ ) {
    print( "j = " + j );
}

print( "test: INIT;CONDITION;ITERATE" );
for ( int j=29 ; j > 25 ; --j ) {
    print( "j = " + j );
}

print( "nested for loops" );
for ( int j = 1; j <= 5; j += 1 ) {
    for ( int k = 1; k <= 10; k += 2 ) {
	print( j + " * " + k + " = " + ( j * k ) );
    }
}

print( "double iterators" );
for ( int j = 1, int k = 10; j < k; ++j, --k ) {
    print( "j = " + j + " and k = " + k );
}
yields:

Code:
[color=green]> test-java-for[/color]

test: ;;
i = 5
i = 4
i = 3
i = 2
i = 1
time for a break!
test: ;CONDITION;
i = 0
i = 1
i = 2
i = 3
i = 4
test: INIT;CONDITION;
i = 1
i = 2
i = 3
i = 4
test: INIT;CONDITION;
j = 6
j = 7
j = 8
j = 9
test: INIT;CONDITION;ITERATE
j = 12
j = 13
j = 14
j = 15
j = 16
j = 17
test: INIT;CONDITION;ITERATE
j = 29
j = 28
j = 27
j = 26
nested for loops
1 * 1 = 1
1 * 3 = 3
1 * 5 = 5
1 * 7 = 7
1 * 9 = 9
2 * 1 = 2
2 * 3 = 6
2 * 5 = 10
2 * 7 = 14
2 * 9 = 18
3 * 1 = 3
3 * 3 = 9
3 * 5 = 15
3 * 7 = 21
3 * 9 = 27
4 * 1 = 4
4 * 3 = 12
4 * 5 = 20
4 * 7 = 28
4 * 9 = 36
5 * 1 = 5
5 * 3 = 15
5 * 5 = 25
5 * 7 = 35
5 * 9 = 45
double iterators
j = 1 and k = 10
j = 2 and k = 9
j = 3 and k = 8
j = 4 and k = 7
j = 5 and k = 6
 

Bale

Minion
I just discovered that this does not work:

Code:
ash for(int i = 1, string page; i < 590; i++, page = visit_url("inv_use.php?pwd&whichitem=9085&ajax=1")) {}

To make it work I had to do this:

Code:
ash for(int i = 1, string page = ""; i < 590; i++, page = visit_url("inv_use.php?pwd&whichitem=9085&ajax=1")) {}
 

Veracity

Developer
Staff member
It is true, I required an initializer. I'll look at it, by and by, to let you omit it to get the default.
 

Veracity

Developer
Staff member
This:

Code:
print( "no assignment" );
for ( int j, string str, int count = 5; count > 0; str += j++, --count ) {
    print( "count = " + count + " j = " + j + " str = \"" + str + "\"" );
}
yields:

Code:
no assignment
count = 5 j = 0 str = ""
count = 4 j = 1 str = "0"
count = 3 j = 2 str = "01"
count = 2 j = 3 str = "012"
count = 1 j = 4 str = "0123"
in revision 17496.

Note that all variables mentioned in the initializer section get initialized, either to what you specify or to the default initial value for the data type. This includes already defined variables - which is an extension I coded for ASH's Java-style for loop:

int a = 12; // new variable in the scope of the loop body, initialized to 12
int a; // ditto, initialized to 0
b = 12; // variable defined in the parent scope, initialized to 12
b; // ditto, initialized to 0

If you simply want to use a pre-defined variable and not initialize it, don't bother mentioning it in the initializer section of the for loop.
 

xKiv

Active member
Unknown variable 'j' ()

Variable j is from elsewhere. It is an infiniloop.

This includes already defined variables - which is an extension I coded for ASH's Java-style for loop:

Do you mean that the already existing variables are reused but reinitialized, or that they get shadowed?

Reused:
Code:
int a=-1;
for (int a; a<0; a++) {} // no execution because 0 is not less than 0
print(a); // zero, because the loop initialized it to default

Shadowed:
Code:
int a=-1;
for (int a; a<0; a++) {}
print(a); // -1, because they are two different variables that just happen to share a name

IIRC java resolves this ambiguity by making it a "duplicate variable" syntax error (but the variable is still only visible *inside* the loop).
At a quick glance, C and C++, have it three ways, depending on standard, compiler, and compile-time options - either the initializer is effectively outside the loop (so it conflicts with preceding declarations of the same variable name, but the variable stays visible after the loop ends), or it's scoped entirely within the loop (shadowed), or it's like java (may not duplicate a previously declared variable, but goes out of scope at the end of the loop, and doesn't prevent a later-defined variable with the same name - obviously this one isn't possible in plain C)
 

Veracity

Developer
Staff member
If you say "int a = 1" in the initializer section, "a" will shadow "a" from outside of the loop. It declares a new variable named "a" whose scope is the loop body. This is how ASH works in general:

Code:
int a = 2;
if ( true )
{
    int a = 1;
    print( "inner a = " + a );
}
print( "outer a = " + a );
yields:

Code:
inner a = 1
outer a = 2
(As an aside, if I omit the "if (true)" - i.e., try to simply have a block - ASH says "Script parsing error (test-init.ash, line 2)". I don't like that. I'll look at it.)

If you say "a = 2" - without the type - in the initializer section of the loop, "a" will look for an existing variable from the surrounding scope and will reuse it; it will initialize it as specified, and its value when the loop exits will be whatever it is after all the processing within the loop. If you omit that initializer, the loop can still use variables from outside the loop and manipulate them and change them that way. The only "extension" is allowing such variables to be put into the initializer section of the loop to be given an initial value, rather than requiring "a = 2;" to be placed in front of the loop.

It would be simple to always require a type and not extend the syntax as described.

In any case, "shadowing" variables without an error or warning is just how ASH works.
 

Veracity

Developer
Staff member
Yeah. Revision 17497 allows this:

Code:
int a = 2;
{
    int a = 1;
    print( "inner a = " + a );
}
print( "outer a = " + a );
 

Bale

Minion
Let's fix the code...

for (int i=1, int j; j < 12; i++) {
print("Thank you "+i+" times!");
}
 
Top