1

At some point I wanted to randomize if an array would be inverted or not while creating it.

One of the first things I figured was this:

bool reverse = Random.value > 0.5f;
for (
        int i = reverse ? steps - 1 : 0; 
        reverse ? i >= 0 : i < steps; 
        i += reverse ? -1 : +1
    ) {
    rotateScript.angles.Add(angleRange[0] + stepAdder * i);
}

Later I realized despite taking more lines, two for loops inside an if/else would be more readable.

But the question remained: Would those ternary conditions be executed each iteration, or just once?

Felipe Müller
  • 225
  • 1
  • 12

2 Answers2

4

Correct, the 2nd and 3rd components of the for statement are evaluated in every iteration.

This:

for( x; y; z ) a;

Is equivalent to:

x;
while( y ) { a; z; }

So y will be evaluated 1 more time than z.

Dai
  • 141,631
  • 28
  • 261
  • 374
  • Thanks. I thought maybe the compiler would do some work inside the parameters, but now it came to me that it wouldn't be able, because I could obviously be changing the value of the "reverse" boolean inside the loop scope. – Felipe Müller May 02 '15 at 05:14
1

As @Dai pointed out, the second and third statements must be evaluated at the end of each iteration.

This behaviour is detailed in §8.8.3 of the C# language specification. Paraphrased, it says about a

for ( initialiser; condition; iterator; ) { ... }

statement:

A for statement is executed as follows:

  • If a for-initializer is present, the variable initializers or statement expressions are executed in the order they are written. This step is only performed once.
  • If a for-condition is present, it is evaluated.
  • If the for-condition is not present or if the evaluation yields true, control is transferred to the embedded statement. When and if control reaches the end point of the embedded statement, the expressions of the for-iterator, are evaluated in sequence, and then another iteration is performed, starting with evaluation of the for-condition in the step above.
  • If the for-condition is present and the evaluation yields false, control is transferred to the end point of the for statement.

With your code

for (
    int i = reverse ? steps - 1 : 0; 
    reverse ? i >= 0 : i < steps; 
    i += reverse ? -1 : +1
) {
    rotateScript.angles.Add(angleRange[0] + stepAdder * i);
}

you do have a few options to make the ternary operator at reach iteration unnecessary.

You mentioned using an if/else with two for loops but I suggest that you do not do that because it duplicates code, which hinders its maintainability, and readability.


Option 1: Use a standard for loop:

You can put the logic into the code inside the loop, i.e.

for ( i = 0; i < steps; i += 1 )
{
    int multiplier = reverse ? steps - 1 - i: i;
    rotateScript.angles.Add(angleRange[0] + stepAdder * multiplier);
}

Option 2: Move the ternary logic out:

Calculate the limit and the increment first, i.e.

int start = reverse ? steps - 1 : 0;
int increment = reverse ? -1 : +1;
int limit = reverse ? -1 : steps;

for ( int i = start; i != limit; i += increment; )
{
    rotateScript.angles.Add(angleRange[0] + stepAdder * i);
}

I prefer option 1 as I think most people find straightforward for loops easier to understand.

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92