each has its own problems in terms of maintainability. Bailing out of the loop early (perhaps an exception was hit, perhaps there was a return or last) will leave the iterator in the middle of the hash.
> perl -wE '
sub p {
my($h) = @_;
while (my($k, $v) = each %$h) { return "$k=$v" }
}
my %h = qw( one 1 two 2 three 3 );
say p(\%h);
say p(\%h);
say p(\%h);
'
three=3
one=1
two=2
This can lead to some subtle hard to trace bugs. I've been personally bitten by this several times, and I've essentially dropped each from my toolkit; it's simply too easy to leave the iterator in a strange spot.
I also wouldn't be too sure of your optimization suggestion. With a pretty basic benchmark I slapped together (source here) it would appear separate keys/values is faster:
> ./each-vs-key-values.pl
BEGIN, hash: short
Benchmark: running each, keys_values for at least 5 CPU seconds...
each: 6 wallclock secs ( 5.26 usr + 0.01 sys = 5.27 CPU) @ 44
+213.85/s (n=233007)
keys_values: 6 wallclock secs ( 5.63 usr + 0.01 sys = 5.64 CPU) @ 1
+07908.33/s (n=608603)
Rate each keys_values
each 44214/s -- -59%
keys_values 107908/s 144% --
END, hash: short
BEGIN, hash: long
Benchmark: running each, keys_values for at least 5 CPU seconds...
each: 7 wallclock secs ( 5.83 usr + 0.00 sys = 5.83 CPU) @ 16
+6.38/s (n=970)
keys_values: 6 wallclock secs ( 5.30 usr + 0.00 sys = 5.30 CPU) @ 6
+95.09/s (n=3684)
Rate each keys_values
each 166/s -- -76%
keys_values 695/s 318% --
END, hash: long
BEGIN, hash: alphabet
Benchmark: running each, keys_values for at least 5 CPU seconds...
each: 5 wallclock secs ( 5.24 usr + 0.01 sys = 5.25 CPU) @ 36
+26.29/s (n=19038)
keys_values: 5 wallclock secs ( 5.20 usr + 0.00 sys = 5.20 CPU) @ 1
+3917.12/s (n=72369)
Rate each keys_values
each 3626/s -- -74%
keys_values 13917/s 284% --
END, hash: alphabet
This is with a Debian Lenny perl 5.10.1. I'm speculating the overhead of the multiple each calls is killing any gains you get from not iterating a second time; that, or the iteration is cheap because of how the HV is built. |