bestprogrammerintheworld
bestprogrammerintheworld

Reputation: 5520

What does this for-loop mean?

I've stumbled upon a syntax in a code example I have never seen in for-loops before in PHP.

What does this do? WHY should I use this?

for(;$i<$max;){
    $i++;
    //code..
}

I could figure out that it was not the same as

for($i=0;$i<$max;$i++) {
    //code...
}

I don't understand the difference between the two examples above.

If for being more specific about my thoughts. If we have this code (taken from a solution from adventofcode):https://www.reddit.com/r/adventofcode/comments/kdf85p/2020_day_15_solutions/

<?php
$cap = 2020;
$bits = [5,1,9,18,13,8,0];
$i=0;
$time = [];
foreach($bits as $bit) {
    $i++;
    $time[$bit] = $i;
    $say = 0;
}

for(;$i<$cap-1;){
    $i++;
    if(isset($time[$say])) {
        $last = $time[$say];
    }
    else {
        $last = $i;
    }
    $time[$say] = $i;
    $say = $i - $last;
}
echo $say;
?>

and compare that to:

<?php
$cap = 2020;
$bits = [5,1,9,18,13,8,0];
$i=0;
$time = [];
foreach($bits as $bit) {
    $i++;
    $time[$bit] = $i;
    $say = 0;
}

for($i=0;$i<$cap-1;$i++){
    if(isset($time[$say])) {
        $last = $time[$say];
    }
    else {
        $last = $i;
    }
    $time[$say] = $i;
    $say = $i - $last;
}
echo $say;
?>

I get different results in $say.(376 in first example and 38 in last example). Why do I get different values?

Upvotes: 0

Views: 264

Answers (4)

Nick
Nick

Reputation: 147146

The main difference between the two blocks (assuming $i is initialised to 0 before the for(;$i<$max;){ loop) is that the first loop increments $i before running the loop code, where the second loop increments $i after running the loop code. As a trivial example:

function code($i) {
    echo "$i\n";
}

$max = 3;
$i = 0;
for(;$i<$max;){
    $i++;
    code($i);
}

for($i=0;$i<$max;$i++) {
    code($i);
}

The output of the first loop is:

1
2
3

while the output of the second loop is:

0
1
2

Note (as pointed out by @IMSoP), the condition clause is executed at the beginning of the loop, and can have side-effects, so you could also emulate the first loop with this code:

for($i=0;$i++<$max;) {
    code($i);
}

Upvotes: 1

IMSoP
IMSoP

Reputation: 97678

C-style for loops are a rather peculiar piece of syntax. They actually consist of three expressions, any of which can do anything you like, or even be empty:

  • An expression to execute for its side effects once before the loop begins
  • An expression to evaluate at the beginning of each iteration, to see if the loop should terminate
  • An expression to execute for its side effects at the end of each iteration

The most common way to use them is:

  • Initialise a counter of some sort
  • Check if the counter has reached some value
  • Increment or decrement the counter

But those aren't built into the language at all, and leaving one of the expressions out doesn't apply any default behaviour, it just does nothing - except that leaving the second expression empty always evaluates to true.

So, for instance:

  • for(;true;) is an infinite loop: it does nothing, checks true, and does nothing again
  • for(;;) is the same infinite loop, because the empty expression in the middle is considered true
  • for($i=0;;) is just the same infinite loop, but with $i initialised to 0 before running it
  • for(;true;foo()) is the same loop, but with the function foo() run at the end of every iteration

In your case, the loop is for(;$i<$max;) which breaks down to:

  • Before starting the loop, do nothing
  • At the beginning of each iteration, terminate if the expression $i<$max happens to be false
  • At the end of each iteration, do nothing

It doesn't do anything to control what values $i and $max have before or during the loop.

In fact, it's just the same as while($i<$max) and would probably be much clearer if written that way.

The example shown seems to have ended up that way because the author wanted to move the $i++ to the beginning of each iteration, rather than the end (although why they also left out the $i=0 I'm not sure). But the for syntax supports that too! You can actually include multiple expressions with a comma between in any of the three positions; if they're in the second position, the last one is what determines if the loop exits.

So you can do this:

for($i=0; $i++,$i<=$max; )

Now, $i will be incremented at the beginning of the loop; since it will be incremented before the test, you have to also adjust the condition from < to <= to make sure it runs for one more iteration.

For that particular case, there's another way as well: incrementing a variable returns a value. If you write ++$i it returns the value after incrementing, and if you write $i++ it returns the value before incrementing. So both of these would also work:

for($i=0; ++$i <= 10; ) echo $i, PHP_EOL;
for($i=0; $i++ < 10; ) echo $i, PHP_EOL;

Upvotes: 1

Ofir Baruch
Ofir Baruch

Reputation: 10346

Well based on the PHP docs: https://www.php.net/manual/en/control-structures.for.php

for loops are the most complex loops in PHP. They behave like their C counterparts. The syntax of a for loop is:

for (expr1; expr2; expr3) statement

While:

Each of the expressions can be empty or contain multiple expressions separated by commas.

So it's just a way to "save code" when your first expression of the for-loop is "obvious", So instead of mentioning the default obvious expression - you just "skip" it.

According to your example:

for(;$i<$cap-1;)

we skipped the first expression (expr1) as $i has been already defined as 0 ($i = 0;) earlier in the code block so it's "skippable". Doesn't affect the code.

But, The third expression:

At the end of each iteration, expr3 is evaluated (executed).

Since we don't mention it in the loop, we are responsible to handle the "increasement" (in this case) of $i in the loop itself.

However - the main difference in the code is that if you mention the third expression - it's evaluated at the end of each iteration but in the code block (your example) - we increase the $i variable at the beginning of the code.

Upvotes: 2

Arturs
Arturs

Reputation: 402

In your first example, $i is registered somewhere before. so $i can be 0 or other zero, because if you use code like

for(;$i<$max;){
    $i++;
    //code..
}

you got error Undefined variable $i in and later $i is registered.

/* example 1 */

for ($i = 1; $i <= 10; $i++) {
    echo $i;
}

/* example 2 */

for ($i = 1; ; $i++) {
    if ($i > 10) {
        break;
    }
    echo $i;
}

/* example 3 */

$i = 1;
for (; ; ) {
    if ($i > 10) {
        break;
    }
    echo $i;
    $i++;
}

https://www.php.net/manual/en/control-structures.for.php

what is your point?

Upvotes: 0

Related Questions