Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Loop Quandary

by joshpk105 (Initiate)
on Nov 21, 2013 at 18:48 UTC ( [id://1063778]=perlquestion: print w/replies, xml ) Need Help??

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

Why does one while loop work, and the other infinite loop?
use strict; use warnings; my $str = 'ababa'; while($str =~ /(a)/g){ # works print $1,$/; } while(InfStr() =~ /(a)/g){ # infinite loop print $1,$/; } sub InfStr{ return 'ababa'; }

Replies are listed 'Best First'.
Re: Loop Quandary
by Crackers2 (Parson) on Nov 21, 2013 at 19:03 UTC

    My guess is in the first loop the match happens on the same string each time, so you'll find each a in turn then exit the loop

    In the second example, you call InfStr on every cycle of the loop, which makes it a regex against a new string, so it'll find the first a in the string each time and never progress

    (Update: You can see this more clearly if you use (.) instead of (a) for the match; first loop will go through each letter, second on will always find the first a)
      Nice explanation. Interestingly, adding the empty prototype to the sub definition and removing return changes the behaviour, as Perl optimizes the sub away:
      sub InfStr () { 'ababa' }

      which is equivalent to

      use constant INFSTR => 'ababa';
      لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Loop Quandary
by ww (Archbishop) on Nov 21, 2013 at 19:06 UTC
    perldoc perlsyn:
    "while" repeats the statement *while* the condition is true.
    $InfStr() is always true.
      $InfStr() is not the while condition here.

      Update:
      The reason first loop ends is because $str stores the necessary magic for m//g.
      Second loop is infinite since InfStr() returns a fresh value each iteration.

      $ perl -MDevel::Peek -e'(my $x = "ababa") =~ m/a/g; print Dump($x);' SV = PVMG(0x7b65a0) at 0x786680 REFCNT = 1 FLAGS = (PADMY,SMG,POK,pPOK) IV = 0 NV = 0 PV = 0x778780 "ababa"\0 CUR = 5 LEN = 8 MAGIC = 0x780ee0 MG_VIRTUAL = &PL_vtbl_mglob MG_TYPE = PERL_MAGIC_regex_global(g) MG_LEN = 1

      Returning a reference from the sub can work around the problem:

      my $x = "ababa"; sub foo { \$x; } print join " ", @-, @+ while ${foo()} =~ m/a/g;

      I hope this explains things a little bit better.

        Before the update oiskuu says in the node above that $InfStr "is not the while condition here. (emphasis supplied)"

        Strictly speaking that's true; in fact $InfStr isn't a condition at all, but that misses the point.

        But that's not what my preceeding node says (omitting the detail that the condition is while(InfStr() =~ /(a)/g){).

        The condition is InfStr() =~ /(a) and it IS always true because the sub always returns a value in which the test is true (My update: And that's pretty much the explanation espoused in oiskuu's "Update" above. And, oh yes, I added the initial phrase in this node to make the thread more readable.)

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (7)
As of 2024-04-19 13:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found