Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Internally, how do for() and while() differ?

by stevieb (Canon)
on Oct 26, 2015 at 23:57 UTC ( [id://1146041]=perlquestion: print w/replies, xml ) Need Help??

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

Looking at making some changes to a module that loops over an array (actually a list, handed off from a file handle, where I'd like to loop on the handle itself).

Internally, do for() and while() do the same thing, ie., are the following equivalent?:

for (<$fh>){ print; } while (<$fh>){ print; }

With that simple example, they seem to do the same thing (in v5.22 on Linux Mint at least). But below the surface, do they really?

-stevieb

Replies are listed 'Best First'.
Re: Internally, how do for() and while() differ?
by BrowserUk (Patriarch) on Oct 27, 2015 at 00:04 UTC
    Do they really?

    No.

    1. The former places the readline in a list context, slurps the whole file and then processes that list in the loop, one line at a time.
    2. The latter places the readline in a scalar context, reads one line at a time and then prints it before looping back to read the next line.

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
    In the absence of evidence, opinion is indistinguishable from prejudice.

      Thank you. That had slipped my mind. It makes total sense.

Re: Internally, how do for() and while() differ?
by AppleFritter (Vicar) on Oct 27, 2015 at 00:04 UTC
    No; the for loop will slurp all of $fh into memory and then iterate over that, whereas while will only read one line at a time.
Re: Internally, how do for() and while() differ?
by shmem (Chancellor) on Oct 27, 2015 at 07:41 UTC

    As others already said, no. Here's what the compiler backend B (B::Terse) says, running

    perl -MO=Terse -le 'for(<>){print}' perl -MO=Terse -le 'while(<>){print}'

    substituting the addresses with 0x? and running 'vimdiff for while':

    ==================== for ====================|=================== while ===================
    LISTOP (0x?) leave [1]                       |  LISTOP (0x?) leave [1]
      OP (0x?) enter                             |    OP (0x?) enter
      COP (0x?) nextstate                        |    COP (0x?) nextstate
      BINOP (0x?) leaveloop                      |    BINOP (0x?) leaveloop
        LOOP (0x?) enteriter                     |      LOOP (0x?) enterloop
          OP (0x?) null [3]                      |  ---------------------------------------------
          UNOP (0x?) null [147]                  |  ---------------------------------------------
            OP (0x?) pushmark                    |  ---------------------------------------------
            UNOP (0x?) readline [2]              |  ---------------------------------------------
              PADOP (0x?) gv  GV (0x?) *ARGV     |  ---------------------------------------------
          PADOP (0x?) gv  GV (0x?) *_            |  ---------------------------------------------
        UNOP (0x?) null                          |      UNOP (0x?) null
          LOGOP (0x?) and                        |        LOGOP (0x?) and
            OP (0x?) iter                        |            UNOP (0x?) defined
    ---------------------------------------------|              UNOP (0x?) null
    ---------------------------------------------|                UNOP (0x?) null [15]
    ---------------------------------------------|                  PADOP (0x?) gvsv  GV (0x?) *_
    ---------------------------------------------|                UNOP (0x?) readline [2]
    ---------------------------------------------|                  PADOP (0x?) gv  GV (0x?) *ARGV
            LISTOP (0x?) lineseq                 |            LISTOP (0x?) lineseq
              COP (0x?) nextstate                |              COP (0x?) nextstate
              LISTOP (0x?) print                 |              LISTOP (0x?) print
                OP (0x?) pushmark                |                OP (0x?) pushmark
                UNOP (0x?) null [15]             |                UNOP (0x?) null [15]
                  PADOP (0x?) gvsv  GV (0x?) *_  |                  PADOP (0x?) gvsv  GV (0x?) *_
              OP (0x?) unstack                   |              OP (0x?) unstack
    
    

    which shows,that for gobbles up all lines (LOOP enteriter) to process each (OP iter) after that, whereas the while loop (LOOP enterloop) processes readline and print in the loop body (LOOP enterloop).

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re: Internally, how do for() and while() differ?
by LanX (Saint) on Oct 27, 2015 at 00:59 UTC
    for iterates over a list, everything in brackets is expanded (the only exception are ranges ). So <> will create a temporary list.

    while loops as long a boolean expression is true.

    This can be used together with an iterator, like while($x=iter()) .

    There is no general automatism to set $_ like your example implies, that's just magic behavior of the file iterator <> in scalar context. that boolean context.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

       There is no general automatism to set $_ like your example implies, that's just magic behavior of the file iterator <> in scalar context.

      Um, not quite, thats part of the magic of while not readline

      $ perl -MO=Deparse,-p -le "while(<>){print}" BEGIN { $/ = "\n"; $\ = "\n"; } while (defined(($_ = <ARGV>))) { print($_); } -e syntax OK $ perl -MO=Deparse,-p -le "while($f=<>){print}" BEGIN { $/ = "\n"; $\ = "\n"; } while (defined(($f = <ARGV>))) { print($_); } -e syntax OK $ echo hi |perl -le "while($f=<>){print}"
      You see  <> in scalar context didn't set $_
        I meant while's scalar context, and only this iterator.

        Should be documented ( perlsyn ? )

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Je suis Charlie!

        UPDATE

        see perlop#IO-Operators :

        > If and only if the input symbol is the only thing inside the conditional of a while statement (even if disguised as a for(;;) loop), the value is automatically assigned to the global variable $_ , destroying whatever was there previously.

Re: Internally, how do for() and while() differ?
by Anonymous Monk on Oct 27, 2015 at 00:38 UTC

    Try it with a really, really big file. :)

Re: Internally, how do for() and while() differ?
by MidLifeXis (Monsignor) on Oct 27, 2015 at 13:36 UTC

    I think you also want to be careful about the truthiness of your input values with while. See defined for an approach.

    Update: Hmm, after testing, I am not sure on this advice. Possibly ignore me.

    Update 2: confirmed -

    while (<>) {...} ... is Perl shorthand for the more explicitly written ... while (defined($line = <ARGV>)) {...}

    --MidLifeXis

Re: Internally, how do for() and while() differ?
by ikegami (Patriarch) on Oct 27, 2015 at 16:07 UTC
    They are not even close to being equivalent, as evidenced by
    my @a = qw( a b c ); for (@a) { print("$_\n"); # Prints "a", then "b", then "c". } while (@a) { print("$_\n"); # Prints an infinite number of blank lines. }

      The two examples are equivalent in operation, since they have the <> operator around a file handle. In the case of arrays, which the OP did not specify, you are correct. Unless, again, the <> operator is used.

      @a = qw(a b c); for(<@a>) { print "$_\n" }; while(<@a>) { print "$_\n" };

      Both produce the same output, the while loop with considerably more efficiency for large datasets.

      Dum Spiro Spero
        > Unless, again, the <> operator is used.

        Sorry for nitpicking, but IMHO it's not the same "operator" here.

        The OP uses a readline and you are applying a glob.*

        That's one of the more confusing magic features of Perl, so I'm open for further discussion on this matter.

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Je suis Charlie!

        *) similarly are range and flipflop different, even when written with ..

Re: Internally, how do for() and while() differ?
by jeffa (Bishop) on Oct 27, 2015 at 17:48 UTC
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://1146041]
Approved by AppleFritter
Front-paged by Discipulus
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (6)
As of 2024-04-23 21:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found