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

Hello Monks,

after a very long time of debugging because of missing options in my application I found a really curious bug.

The two while loops are added just for debugging into the method:
sub _split_options { my ($self, $opts) = @_; while (my ($k, $v) = each %$opts) { print "$k = $v\n"; } while (my ($k, $v) = each %$opts) { print "$k = $v\n"; } # ... another code }
The first while-loop prints out 3 keys with 3 values. The seconds while-loop prints out 4 keys and 4 values. The loops runs one after another. The code is exaclty the same. I am totaly confused. I tried to reprodruce this bug in another code snippets but without success.

If I replace the first loop with foreach I don't have the problem and it prints out 4 keys and 4 values.

My Perl Version is 5.10.0 on a Debian Lenny.

Jonny

Replies are listed 'Best First'.
Re: Found bug: while()
by ikegami (Patriarch) on Oct 13, 2009 at 03:33 UTC

    It means you've already started iterating over the hash.

    sub _split_options { my ($opts) = @_; while (my ($k, $v) = each %$opts) { print "$k = $v\n"; } print("\n"); while (my ($k, $v) = each %$opts) { print "$k = $v\n"; } } my %opts = qw( a 1 b 2 c 3 d 4 ); scalar each %opts; _split_options(\%opts);
    a = 1 b = 2 d = 4 c = 3 a = 1 b = 2 d = 4

    So no, it's not a bug in while, or even with each. It's a bug in your use of each. Whenever you use each, you should reset the iterator first. You can do that efficiently by calling keys in void context first.

    sub _split_options { my ($opts) = @_; keys %$opts; # Reset iterator while (my ($k, $v) = each %$opts) { print "$k = $v\n"; } print("\n"); #keys %$opts; # Previous loop reset iterator while (my ($k, $v) = each %$opts) { print "$k = $v\n"; } } my %opts = qw( a 1 b 2 c 3 d 4 ); scalar each %opts; _split_options(\%opts);
    c = 3 a = 1 b = 2 d = 4 c = 3 a = 1 b = 2 d = 4
      Ok :-)

      Thank you for your fast feedback!