I subscribe to the idea that variables shouldn't be initialized until right before you're going to use them. It makes it a lot easier to remember what a variable represents if it's by the code that will consume it, and it diminishes the chance that the variable will be misused between initialisation and proper use.
The problems comes when the use of that variable is inside a loop or two. Then, 开发者_StackOverflow中文版the cost of intialisation gets multiplied and it may begin to impact performance.
Within Perl (or generally, as appropriate), are their any neat little techniques that allow you to place the initialization of a variable within a loop, but such that it only gets initialized on the first pass?
I'd thought of something like:
my $variable = undef;
while ($outer_loop) {
while ($inner_loop) {
$variable = $variable || 'initial_value'
}
}
NB: The implication is that $variable
is not reassigned within the loop.
Now maybe it's me, but that seems a little inelegant.
So, here's my question: is there a neater way to do this, or do I just need to get overmyself and compromise on code organisation, or suck up that 'inelegant' solution above?
To address issues in your comment (the variable is computed in a function):
A standard technique for optimizing this sort of logic that you want is called memoization (of that function). Among other approaches, Perl has
Memoize
module, or you can do it yourself.use Memoize; memoize('slow_function'); while ($outer_loop) { while ($inner_loop) { my $variable = slow_function(arguments); } }
Also, if the function is always producing 100% identical value (by design) throughout the loop, simply do a poor-mans memoization by initializing the variable in a statement prior to the loop.
If you have a loop 3 pages long (e.g. so long that having the initialization before the loop is a readability problem compared to inside the loop), you have a bigger coding problem than just the location of the initialization line, and need to re-factor your code in the first place.
As an aside, if your only concern with placing the variable before the loop is the fact that it destroys the readability context of "this variable is only for use inside this loop", you can easily solve it by either:
Having well documented code - either name the variable accordingly, or add a comment to initialization line, or both.
Or, by naming a variable something like
my $default_value_for_next_loop = long_func();
, and inside the loop actually create a local loop variable initialized from that:my $loop_var = $default_value_for_next_loop;
Also, as far as your own approach ($variable = $variable || 'initial_value';
);
I personally find that absolutely elegant and readable, BUT!!! I'm pretty sure that it actually performs worse than a straight-up $variable = $default_value_for_next_loop;
, because it has a conditional statement instead of a straight assignment. But I can't be certain without benchmarking.
The problems comes when the use of that variable is inside a loop or two. Then, the cost of intialisation gets multiplied and it may begin to impact performance.
Does it? Have you measured it? If your $variable
applies to the code throughout both loops, then I would write your loop as follows:
my $variable = 'initial_value';
while ($outer_loop) {
while ($inner_loop) {
# ...
}
}
That way, the reader knows that $variable
is used in the following section of code, and what its initial value is. In your code snippet, the reader has to go find the actual initial value somewhere deep in the loop.
There is unlikely to be a performance problem here, but you should always measure the performance if that is a critical factor.
I think you're taking your guideline a little too far. The best way to stop misuse of a variable is to delay it's declaration until just before it's needed. (Thus limiting it to smallest possible lexical scope.) Delaying initialization doesn't prevent misuse; it just creates an opportunity for someone to use an undefined value, preempt your initialization with their own, or use your variable for a completely unrelated purpose.
If a variable requires an initial/default value, that should be done as part of the declaration if possible. This makes it clear that the variable has a starting value.
my $x = 1;
my $y = f($x);
Delaying the initialization implies that there isn't an initial value. That's fine if there isn't one or if you can't determine it ahead of time, but you sacrifice clarity by sneaking a $var //= 'value'
in later.
For variables that need to retain their value across loop iterations you have to declare them outside the loop. Sometimes I wrap loops in an extra block to prevent those variables from leaking into the following code:
{
my $i = 5;
for (1 .. 10) {
say $i++;
}
}
精彩评论