Skeeve has asked for the wisdom of the Perl Monks concerning the following question:

I already found the solution thanks to Corion in the Chatterbox but I'm still unsure what's going on here.

When I coded this

$File::Find::prune= not $recurse and ($File::Find::dir ne $File::F +ind::topdir);

I got a "useless use of string ne in void context".

Putting parentheses around the code helped:

$File::Find::prune= (not $recurse and ($File::Find::dir ne $File:: +Find::topdir));

But I don't understand why. Can someone please enlighten me?

Update: Thanks to those who replied! Now I do understand!


s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%
+.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e&&s""`$''`"e

Replies are listed 'Best First'.
Re: Need explanation for: useless use of string ne in void context
by Fletch (Bishop) on Jan 06, 2009 at 14:15 UTC

    As is pretty much always the case with parsing questions, B::Deparse is your friend.

    $ perl -MO=Deparse,-p,-q -we '$File::Find::prune= not $recurse and ($F +ile::Find::dir ne $File::Find::topdir);' Useless use of string ne in void context at -e line 1. Name "File::Find::prune" used only once: possible typo at -e line 1. Name "File::Find::topdir" used only once: possible typo at -e line 1. Name "File::Find::dir" used only once: possible typo at -e line 1. Name "main::recurse" used only once: possible typo at -e line 1. BEGIN { $^W = 1; } (($File::Find::prune = (!$recurse)) and ($File::Find::dir ne $File::Fi +nd::topdir)); -e syntax OK

    and has a lower precedence than =; I think in fact someone posted a meditation on just this problem not last week.

    Update: Meh, it was two weeks ago: Burned by precedence rules.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Need explanation for: useless use of string ne in void context
by Corion (Patriarch) on Jan 06, 2009 at 14:20 UTC

    The quick answer is that and binds less tight than parentheses or &&. The long answer is to first look at what Perl sees:

    >perl -MO=Deparse -e "$File::Find::prune= not $recurse and ($File::Fin +d::dir ne $File::Find::topdir);" $File::Find::dir ne $File::Find::topdir if $File::Find::prune = !$recu +rse;

    So we now see that Perl doesn't group what "we" see as an expression together, but splits it in two. To group together what we want together, we can use parentheses (like you did), or the sigil-versions of operators, which do bind tighter:

    >perl -MO=Deparse -e "$File::Find::prune= not $recurse && ($File::Find +::dir ne $File::Find::topdir);" $File::Find::prune = !($recurse && $File::Find::dir ne $File::Find::to +pdir);

    Having the two kinds of operators isn't all weird, because the more lax binding operators are incredibly convenient when writing code that depends on the return value of statements when you don't want parentheses:

    open my $fh, $file or die "Couldn't open '$file': $!";

    If or did bind as close as ||, then you would need parentheses:

    open (my $fh, $file) || die "Couldn't open '$file': $!";

    Otherwise, Perl interprets things "wrong again", and groups $filename || die ... together:

    >perl -MO=Deparse -e "open my $fh, $filename || die qq(couldn't open $ +filename: $!)" open my $fh, $filename || die("couldn't open ${filename}: $!"); -e syntax OK >perl -MO=Deparse -e "open my $fh, $filename or die qq(couldn't open $ +filename: $!)" die "couldn't open ${filename}: $!" unless open my $fh, $filename; -e syntax OK
      The quick answer is that and binds less tight than parentheses or &&.

      That's true, but not relevant in this case. What matters is that 'and' binds less tight than assignment.