Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask

while( each ... ) caught in an infinite loop

by johngg (Canon)
on Mar 31, 2009 at 10:34 UTC ( #754380=perlquestion: print w/replies, xml ) Need Help??

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

I have a script that seems to hang and I have narrowed the problem down to the point where the code iterates, using each, over a de-referenced hash reference that is returned by a subroutine, i.e. each %{ sub { return { ... } }->( ... ) }. The each call keeps returning the first key/value pair rather than presenting the pairs in turn, thus looping for ever. The hang can be cured by storing the returned reference in an intermediate scalar variable before doing the each but I am curious as to why each is failing in this case. The documentation says:-

... There is a single iterator for each hash, shared by all each, keys, and values function calls in the program; it can be reset by reading all the elements from the hash, or by evaluating keys HASH or values HASH. ...

which might imply that keys and values would also have problems in this construct but that is not the case. The following code presents a minimal working example to demonstrate the problem. It first runs the code using the intermediate scalar variable and then repeats the exercise without it. Note that I am forced to bail out of the while( ( $k, $v ) = each %{ ... } ) { ... } using a counter to avoid an infinite loop.

use strict; use warnings; my @keys = qw{ A B C D }; my( $k, $v ); print q{-} x 20, qq{\n}; my $hashref = sub { return { map { $_, shift } @keys } }->( 1 .. 4 ); print qq{ Keys: @{ [ keys %{ $hashref } ] }\n}; print qq{Values: @{ [ values %{ $hashref } ] }\n}; print qq{ Each:\n}; print qq{ $k => $v\n} while ( $k, $v ) = each %{ $hashref }; print q{-} x 20, qq{\n}; print qq{ Keys: @{ [ keys %{ sub { return { map { $_, shift } @keys } }->( 1 .. 4 ) } ] }\n}; print qq{Values: @{ [ values %{ sub { return { map { $_, shift } @keys } }->( 1 .. 4 ) } ] }\n}; print qq{ Each:\n}; my $count = 0; while( ( $k, $v ) = each %{ sub { return { map { $_, shift } @keys } }->( 1 .. 4 ) } ) { last if ++ $count > 5; print qq{ $k => $v\n}; } print q{-} x 20, qq{\n};

The output.

-------------------- Keys: A D C B Values: 1 4 3 2 Each: A => 1 D => 4 C => 3 B => 2 -------------------- Keys: A D C B Values: 1 4 3 2 Each: A => 1 A => 1 A => 1 A => 1 A => 1 --------------------

As you can see, while keys and values produce the expected output when dispensing with the intermediate scalar, each gets nowhere fast. I have tested the code using Perl 5.10.0 under Cygwin and ActiveState Perl 5.8.8 under Windows XP.

The fact that the interpreter accepts the syntax and the each attempts to iterate over the hash and fails where keys and values succeed makes me wonder whether this is, perhaps, a small bugette rather than my code trying to do something outside the bounds of the language. Should each be able to operate directly on the de-referenced return from the subroutine just like keys and values or is my code invalid?



Replies are listed 'Best First'.
Re: while( each ... ) caught in an infinite loop
by BrowserUk (Patriarch) on Mar 31, 2009 at 10:44 UTC

    You are calling the subroutine again each time the while loop iterates, which means you are constructing and returning a new anonymous hash for each iteration. As the hashref returned is to a newly construct hash, its iterator starts from the beginning each time.

    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".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      Which, I believe can be constructed from a much smaller example:

      while( my @a = each %{{ a=>'b' }} ) { print "forever\n" }


      Thank you. The "small bugette" is in my brain, obviously. I wonder how it is that I can spend hours on a problem and dismally fail to spot the obvious :-(

      Thanks again.


        It's not at all intuative. I may never have noticed this myself if it wasn't for reading about it in DBM::Deep.


Log In?

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

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (4)
As of 2022-10-05 06:18 GMT
Find Nodes?
    Voting Booth?
    My preferred way to holiday/vacation is:

    Results (20 votes). Check out past polls.