Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl: Why is it slower to declare (my) variables inside a loop?

What's the difference, from the interpreter's POV, between the following the following programs:

#!/usr/bin/perl -w

use strict;

for (1..10000000) {
    my $jimmy = $_**2;
}

and

#!/usr/bin/perl -w

use strict;

my $jimmy;
for (1..10000000) {
    $jimmy = $_**2;
}

"time" reports for the first program:

real    0m1.519s
user    0m1.513s
sys     0m0.004s

and for the second:

real    0m1.023s
user    0m1.012s
sys     0m0.002s
like image 464
flies Avatar asked Jul 23 '10 19:07

flies


People also ask

Is it bad practice to declare variables in a loop?

It's not a problem to define a variable within a loop. In fact, it's good practice, since identifiers should be confined to the smallest possible scope. What's bad is to assign a variable within a loop if you could just as well assign it once before the loop runs.

Should I declare variable before loop?

All the variables which are used in the program are declared in the beginning. It is better to declare the variable in the loop as its validity will be only up to that block and the code can stand alone for that section. So, to tell there is no difference in anything if either of the approaches are used.

How do we tell the difference between code that is inside the loop and code that is outside the loop?

The difference is the scope of the variables. In case you define the variable outside of the loop in can be accessed in a bigger scope.

How are statements terminated in Perl?

every statement in Perl must end with a semicolon(;).


2 Answers

The my declaration in Perl has two primary effects; a compile-time one (wherein it allocates a slot on the containing sub's scratchpad, and makes sure that all references to that name within the proper scope are resolved to that particular scratchpad slot), and a runtime one (wherein it resets the value of that pad slot to undef, or to some particular value if you wrote my $var = foo).

The compile-time portion of course has zero amortized runtime cost, but the runtime portion is run once each time execution passes the my declaration. As others have pointed out, your two examples have different performance because they have different semantics in general -- one clears the variable every time through the loop, and the other doesn't.

like image 89
hobbs Avatar answered Sep 24 '22 15:09

hobbs


Since the example programs you have given do not really do anything it is hard to give you a specific reason why one type of declaration would be better than the other. As many other posters have pointed out, declaring the variable in the loop creates a new variable each time. In your examples that creation is redundant, but consider the following examples using closures.

my @closures;
my $jimmy;

for (1 .. 10) {
    $jimmy = $_** 2;
    push @closures, sub {print "$jimmy\n"};
}

and this one:

my @closures;

for (1 .. 10) {
    my $jimmy = $_** 2;
    push @closures, sub {print "$jimmy\n"};
}

In each case the code builds up a series of code references, but in the first example since all the code refs refer to the same $jimmy each one will print 100 when called. In the second example each code ref will print a different number (1, 4, 9, 16, 25, ...)

So in this case the time difference does not really matter since the two blocks of code do very different things.

like image 33
Eric Strom Avatar answered Sep 22 '22 15:09

Eric Strom