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?

Cheers,

JohnGG


In reply to while( each ... ) caught in an infinite loop by johngg

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.