in reply to Making each(@ary) work on 5.10?

An approach free from tie: Call a subroutine that returns a subref as an iterator.

use strict; use warnings; my @array = qw( this that the other ); # The iterator factory: Call as "my $each = make_each_array( @some_arr +ay );" # Use the iterator as "my( $index, $value ) = $each->();" sub make_each_array (\@) { my $aref = shift; my $idx = 0; return sub { my $reset = shift; if( defined $reset ) { die "Subscript ($reset) for each_array reset is out of ran +ge 0 .. $#{$aref}" if $reset < 0 || $reset > $#{$aref}; $idx = $reset; return; } if( $idx == @{$aref} ) { $idx = 0; return; } my $current_idx = $idx++; return ( $current_idx, $aref->[$current_idx] ); } } my $each_array = make_each_array( @array ); # A simple while() loop: The most common use case for 'each'. while( my( $idx, $value ) = $each_array->() ) { print "$idx => $value\n"; } # Here 'each' has been reset to zero automatically, just like Perl's e +ach. my ( $idx, $value ) = $each_array->(); print "$idx => $value\n"; # Here we explicitly reset 'each' to zero. $each_array->(0); ( $idx, $value ) = $each_array->(); print "$idx => $value\n"; # Here we explicitly reset 'each' to some non-zero index. $each_array->(3); ( $idx, $value ) = $each_array->(); print "$idx => $value\n";

This takes a functional approach: You call make_each_array by passing it the array for which you would like to have an iterator. An iterator is returned. This iterator behaves a lot like each when applied to an array, except that you don't use keys to reset it prematurely. If you want to reset it before reaching the final element of the array, just call the iterator with some value within the array's range (0 through whatever). When you're done with it, let it fall out of scope.

If you do call the iterator after reaching the final element, it returns undef in scalar context, or an empty list in list context. That behavior is just about identical to each. And also in keeping with how each works, if you call the iterator again, it will have reset itself to the zeroth element again to start over.

I used a prototype so that the array would be passed by reference implicitly. There are disadvantages to prototypes too (for example, you can't simply pass an arrayref now; you have to dereference it). If that's a problem, remove the prototyping and pass by reference explicitly.

Do keep in mind that List::MoreUtils has an "each_array" function, but it works a little differently. For one thing, unlike each, it only returns the values, one by one. It doesn't return the index. However, if you don't care about the index, use it instead. It's written in XS, fairly well tested, and already available in a widely used module.


Dave