It starts with a tweet.

I thought about it for a while.

I think that bears further explanation. Classic for loops look like:

for ( my $i = 0 ; $i < 20 ; $i++ ) { ... }

and that’s all fine, but to be honest, I hardly use that form. Most of my Perl uses of for are much like

for my $i ( @array ) { ... }

and Perl handles iterating through the entries in the array. So, to me, it is purpose-built for static data sets. You don’t have to, though.

# this is a perfectly valid memory-sucking infinite loop
for my $i ( @array ) {
    push @array, $i * 2;
}

while, however, is built for when the size of the problem set is dynamic and unset. If you want to start now and keep going until it’s over, that’s when you pull out while.

while ( @array ) {
    shift @array;
}

But clearly, you can do my while stuff in a for loop, and mechanic ways to do for stuff in a while loop. So let’s get back to Mohammad’s question. How do we determine what’s mroe performant?

Friends, this is where we go to Benchmark. In my case, I didn’t want to either wait forever or set fire to my laptop, so I went smaller numbers. Make a list of 1000, loop through it a million times. If you want to find the best (meaning most performant) way to do a thing, this is how we go.

#!/usr/bin/env perl

use strict;
use warnings;
use Benchmark qw(:all);

my $count = 1_000_000;
timethese(
    $count,
    {
        'ForLoop' => sub {
            my @array = 1 .. 1000;
            for (@array) {
                shift @array;
            }
        },
        'WhileLoop' => sub {
            my @array = 1 .. 1000;
            for (@array) {
                shift @array;
            }
        },
    }
);

The only difference is that one, we have an iterator going through an array, and one is getting a conditional. I ran this, made conclusions, but didn’t realize I wasn’t running for vs while but instead for vs for. I put it in a Gist and everything. SIlly Dave.

So, right now, I’m running it again, with slightly bigger numbers.

#!/usr/bin/env perl

use strict;
use warnings;
use Benchmark qw(:all);

my $count = 10_000;
timethese(
    $count,
    {
        'ForLoop' => sub {
            my @array = 1 .. 10_000;
            for (@array) {
                shift @array;
            }
        },
        'WhileLoop' => sub {
            my @array = 1 .. 10_000;
            while (@array) {
                shift @array;
            }
        },
    }
);
./forwhile.pl 
Benchmark: timing 10000 iterations of ForLoop, WhileLoop...
   ForLoop:  4 wallclock secs ( 2.69 usr +  0.02 sys =  2.71 CPU) @ 3690.04/s (n=10000)
 WhileLoop:  5 wallclock secs ( 3.55 usr +  0.00 sys =  3.55 CPU) @ 2816.90/s (n=10000)

That’s a difference toward preferencing for over while, but again, I’m strongly for purposeful use. The numbers say WhileLoop is slightly slower, but the purpose I use them for makes it more understandable to me.

If you have any questions or comments, I would be glad to hear it. Ask me on Twitter or make an issue on my blog repo.