tags:

views:

87

answers:

2

I found this in Mail::IMAPClient. Where does the $_ in $SEARCH_KEYS{ uc($_) } come from?

sub _quote_search {
    my ( $self, @args ) = @_;
    my @ret;
    foreach my $v (@args) {
        if ( ref($v) eq "SCALAR" ) {
            push( @ret, $$v );
        }
        elsif ( exists $SEARCH_KEYS{ uc($_) } ) {
            push( @ret, $v );
        }
        elsif ( @args == 1 ) {
            push( @ret, $v );    # <3.17 compat: caller responsible for quoting
        }
        else {
            push( @ret, $self->Quote($v) );
        }
    }
    return @ret;
}
+7  A: 

That looks to me like a typo where the author converted an anonymous for loop foreach (@args) to one with an explicit iterator variable foreach my $v (@args) and forgot to convert all the incidences of $_ to $v.

You should probably file a bug against the distribution on CPAN.

Ether
I wrote a report.
sid_com
+1  A: 

Even though this is probably a bug, lets consider how this code behaves.

The value of $_ will be determined by the current dynamic scope. What this means is that $_ will have whatever value (the dynamically scoped copy of) $_ has in the calling subroutine.

So for example if I have:

for (1 .. 5 ) {
    foo();
    bar();
}

sub foo {
     print "\$_ = $_\n";
}

sub bar {

    for ( 'a' .. 'c' ) {
        foo();
    }
}

You get output like:

$_ = 1
$_ = a
$_ = b
$_ = c
$_ = 2
$_ = a
$_ = b
$_ = c
...

It gets a little weirder in Perl 5.10 and up, where a lexical $_ exists.

for (1 .. 5 ) {
    foo();
    bar();
}

sub foo {
     print "\$_ = $_\n";
}

sub bar {
    my $_;
    for ( 'a' .. 'c' ) {
        foo();
    }
}

Run this and get:

$_ = 1
$_ = 1
$_ = 1
$_ = 1
$_ = 2
$_ = 2
$_ = 2
$_ = 2

As you can see, if this isn't a bug, it's probably a bad idea.

daotoad
@daotoad => have you found any good uses for lexical `$_`?
Eric Strom
Does the lexicaliced $_ keep the value?This doesn't work: $_ = 10; { my $_; say; }
sid_com
Ok, maybe it's the foo, that keeps the value.
sid_com
@Eric, not really, but 99% of my work needs to be Perl 5.8 compatible. It is important to consider when looking at the posted code.
daotoad
@sid, `$_` is a global variable that gets a new dynamic scope (like you get via `local`) in each for loop. So `foo()` is just printing whatever value is in what `$_` points to at the time it is called. `bar` localizes `$_`, and so it now points to a different value. Take a look at Coping With Scoping. It goes into detail on how dynamic scoping works. http://perl.plover.com/FAQs/Namespaces.html#Just_the_FAQs_Coping_with_Scopi
daotoad