Some languages don't allow you to put your variables where you need them, they force you to declare things up front. C is like this, but this was fixed in C++. Perl allows you to declare variables virtually anywhere, which keeps things neat and tidy.
My advice is to keep your variable definitions as close as possible to where they are used, or to group them together logically in a sensible location. These can sometimes be contradictory, though, so it's often a matter of judgement.
There are advantages to both strategies.
Each sub-routine is like a mini program. It has "globals", it has local variables, and it has sub-blocks that have their own variables. In a recursive sense, the same rules you use to organize your main program apply to each sub-block, all the way down.
Here's an example of what I would categorize as poor technique:
sub foo
{
my ($foobar, $frurab) = @_;
my @foo = split(/,/, $foobar);
my $bar;
my $x;
foreach $x (@$frurab)
{
$bar .= $x->foo();
}
foreach $x (@foo)
{
$bar = "<$x>$bar</$x>";
}
return $bar;
}
Something that can set people's hair on fire is these
Omni-Variables, these things called $x or $i or $foo which take on completely different roles at different points. In this example, $x is an object, and then later, a scalar. Talk about a personality disorder. When debugging, there is no certainty about
what $x is going to be. If, instead, each
foreach loop had its own properly named variable, things would be quite clear.
Also, the @foo variable is not very useful, and seems to just take up space for most of the routine even though it is used only briefly. You could just inline the split and save yourself the variable and the associated memory overhead.
Here's take 2:
sub foo
{
my ($foobar, $frurabs) = @_;
my $return;
foreach my $frurab_entry (@$frurabs)
{
$return .= $frurab_entry->foo();
}
foreach my $tag (split(/,/, $foobar))
{
$return = "<$tag>$return</$tag>";
}
return $return;
}
Now you have two different variables, each named specifically according to what they are. Now, instead of wondering what your seecond loop was iterating over, and having to check back in the function to find out, it is presented right there for you to see.
It's kind of like a "Just In Time" delivery system, only for variables. You don't keep stuff laying around. You create it when you need it, and you get rid of it as soon as possible. Remember that as soon as your
foreach loop ends, all the local variables are liberated, and with them, any memory used. In big, deep functions, this can really cut back on resource consumption.
In the second example, the split version of $foobar is created and used and destroyed in a relatively brief period of time. In the former, it persists for the entire duration of the function, which could be some time. You can imagine how lots of little things like this can add up to a really big thing.