Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Why/how are these different?

by perl-diddler (Chaplain)
on Jan 31, 2013 at 02:49 UTC ( [id://1016196]=perlquestion: print w/replies, xml ) Need Help??

perl-diddler has asked for the wisdom of the Perl Monks concerning the following question:

I have two snippets of code and I was wondering why they produced different results (P is like printf w/auto LF).

> perl -E ' use P; for ($_=3;$_-- >0;) { P "_=%s", $_ }' _=2 _=1 _=0
> perl -E ' use P; P "_=%s", $_ for $_=3;$_-- >0; ' _=3

Note, I didn't say "for my $i...". That would make sense. But the behavior seems like that's what it did. However, a similar construct the reversed "if", doesn't act this way:

> perl -E ' use P; $_=1; P "_=$_" if --$_; > P "got to end w/_=%s", $_; > ' got to end w/_=0 #alternatively: > perl -E ' use P; $_=12; P "_=$_" if --$_; P "got to end w/_=%s", $_; ' _=11 got to end w/_=11

This is in perl 5.16.1. Could someone explain why these look inconsistent to me? (i.e. "$_" value in the conditional statement isn't consistent with it's value in the test or outside the loop.

Thanks!
Curious one.

---
FWIW -- the postfix 'while' seems to be consistent, giving the same results in regular vs. postfix form;

Replies are listed 'Best First'.
Re: Why/how are these different?
by Athanasius (Archbishop) on Jan 31, 2013 at 03:22 UTC

    Perl has two for loops:

    1. C-style: for (...; ...; ...) { ... }

    2. List-style (foreach): for (LIST) { ... }

    Only the second (“foreach”) is available as a statement modifier:

    EXPRESSION for LIST;

    So in the second example, the code is effectively:

    printf "_=%s\n", $_ for $_ = 3; $_-- > 0;

    The first line prints _=3, the second line decrements $_ but has no other effect.

    Update: Even for one-liners, you should turn on warnings:

    perl -wE ...

    This often gives an insight into what Perl understands your code to be. For example:

    13:44 >perl -wE "printf qq[_=%s], $_ for $_ = 3; $_-- > 0;" Useless use of numeric gt (>) in void context at -e line 1. _=3 13:45 >

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Wow...(warnings...duh!)....(doi!))

      I didn't know they were different like that. How perverse! Too bad they didn't limit it to 'foreach' and created the confusion. I can't think of any other places where this could arise, off hand, but are there?

      I noted that if I put parens around the args of the 'for', as in the prefix'd form, I get errors.

      Hmmm...So even when you are clearly trying to use a postfix form, it throws an error instead of allowing it (though I understand why). I just can't figure out why it would have been designed that way.

      And to think I stayed away from 'foreach' specifically because many books recommend doing so because it uses more memory (and I'm working with large arrays)...

        How perverse! Too bad they didn't limit it to 'foreach' and created the confusion.

        From the Camel Book (4th Edition, 2012, page 142):

        For historical reasons, the foreach keyword is a synonym for the for keyword, so you can use for and foreach interchangeably, whichever you think is more readable in a given situation. We tend to prefer for because we are lazy and because it is more readable, especially with the my. (Don’t worry—Perl can easily distinguish for (@ARGV) from for ($i=0; $i<$#ARGV; $i++) because the latter contains semicolons.)
        And to think I stayed away from 'foreach' specifically because many books recommend doing so because it uses more memory (and I'm working with large arrays)...

        I could be wrong, but I think this advice is outdated (if it was ever correct). Again from the Camel Book (page 143):

        If LIST consists of assignable values (meaning variables, generally, not enumerated constants), you can modify each of those variables by modifying VAR inside the loop. That’s because the loop variable becomes an implicit alias for each item in the list that you’re looping over.

        If I’m reading that correctly, no copying is needed, so there’s no reason a foreach-style loop would use more memory than a C-style for loop.

        And there are significant benefits. See Foreach Loops in perlsyn, where a C-style for loop is rewritten as a foreach-style loop in idiomatic Perl, and the latter is stated to be “cleaner, safer, and faster.” And the Camel Book has this in its cosideration of “Time Efficiency” (pages 691–2):

        Avoid subscripting when a foreach or list operator will do.... There’s often a better way to do it. Consider using foreach, shift, and splice operations.

        Hope that helps,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

        [Use of warnings] often gives an insight into what Perl understands your code to be. (Athanasius)

        perl-diddler: Another path to insight is to have Perl deparse your code for you (see B::Deparse and O):

        >perl -wMstrict -MO=Deparse,-p -le "print qq{\$_ '$_'} for $_ = 3; $_-- >0; " Useless use of numeric gt (>) in void context at -e line 1. BEGIN { $^W = 1; } BEGIN { $/ = "\n"; $\ = "\n"; } use strict 'refs'; print("\$_ '${_}'") foreach (($_ = 3)); (($_--) > 0); -e syntax OK
A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1016196]
Approved by Athanasius
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (4)
As of 2024-04-25 12:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found