t'mo has asked for the wisdom of the Perl Monks concerning the following question:

What, if any, are the benefits and dangers of using $_ within nested loops? For example:

my %cds = ( classical => [ [ 'Mozart', 'Requiem' ], [ 'Beethoven', '3rd Symphony' ] ], rock => [ [ 'Van Halen', '1984' ] ], jazz => [ [ 'Miles Davis', 'Birth of the Cool' ], [ 'Stan Getz', 'Brothers' ] ], ); for( sort keys %cds ) { print $_, ": ", scalar @{ $cds{$_} }, " in group\n"; for( @{ $cds{$_} } ) { print "\t", join(",", @{ $_ }), "\n"; } }

My question concerns using $_ in the inner loop of this example. Is is possible I'll destroy the value in $_ of the outer loop by creating the second for loop? Do I even need to worry about it, since I've already used the array reference in $_ by the time I enter the inner loop? Or is there a more evil threat that the inner loop itself will become corrupt?

# "for( ... ) { ... }" creates assignment to $_, right? # doesn't this 'corrupt' value for looking up $cds{$_} ? for( @{ $cds{$_} } ) { ... }

And if variable scoping would solve my percieved problem, understand that the issue of my vs. local is something I don't grok yet. I completely understand my, but local escapes me.

The odd thing is that I ran something like this, with -w and use strict;, and it worked! Why? Should it have worked?

Replies are listed 'Best First'.
Re: Using $_ in nested loops
by merlyn (Sage) on Jan 12, 2001 at 10:38 UTC
    The odd thing is that I ran something like this, with -w and use strict;, and it worked! Why? Should it have worked?
    Yes, and thank goodness it does. I never think about outer variables when coding the foreach loop, thanks to the automatic localization. And as you've discovered, the localization of the control variable happens after the list has been computed. Yes! thank you larry!

    -- Randal L. Schwartz, Perl hacker

Re: Using $_ in nested loops
by btrott (Parson) on Jan 12, 2001 at 10:42 UTC
    > And if variable scoping would solve my percieved problem, > understand that the issue of my vs. local is something I > don't grok yet. I completely understand my, but local > escapes me.
    Calling local on a list of variables modifies the values of those variables to be "local" to the current block, and to any subroutines called from within that block. It does this by saving the value of the variable before you called local, then restoring the value after the block has ended (or some variation on this; it may be more complex. :)

    Take a look at perlsub (Temporary Values via local()) for a better explanation.

    You also wrote:

    > The odd thing is that I ran something like this, with > -w and use strict;, and it worked! Why? Should it have > worked?
    Sure: what you did isn't illegal by any means, and in some circumstances, it's probably exactly what you want.
Re: Using $_ in nested loops
by repson (Chaplain) on Jan 12, 2001 at 13:58 UTC
    A for (@ary) {} is like for local $_ (@ary) {}. So when using for(?:each)? loops it is safe to nest as much as you like......but

    for loops are almost the only thing which automatically localises $_. While loops do not. New scopes do not. New packages/files do not. maps and greps do. foreach does. Three argument for does not. And theres probably more things I should be listing.

    for (@files) { open FILE, $_; while (<FILE>) { push @res, grep {ord($_)<128} split //, $_; } close FILE; }
    Be careful, know what's happening and don't overuse $_ where using sensible variable names would be more sensible.
Re: Using $_ in nested loops
by a (Friar) on Jan 12, 2001 at 10:43 UTC
    Better monks than I will have the real answer, but
    a) local vs my; you generally mean 'my'. Local is/should be used for true global vars ($|, $/ etc) that you want to modify w/i a certain context (I want to say lexical context, but I may just mean 'block') but leave unaffected elsewhere. You'll find my/local will "work" interchangeably for far too much code but that doesn't make local the right choice.
    b) I believe for loops localize $_ automagically, so you need not worry about messing w/ enclosing loops' $_ w/i and enclosed loop. You can think of local here as like a stack; enter a new loop and $_'s value get stacked, so when you exit that loop - pop! and the outer loop's $_ gets restored.

    Hope that isn't 100% wrong ...

    a

      automagically

      Nice word...

      The whole idea of making a stack of $_ makes sense. Thanks!