Perl overload @{} so that you can supply an object to foreach()
The problem that you're having here is not the difference between @{...}
and <...>
but the difference between foreach
and while
.
A while
loop acts a bit like an iterator in as much as its execution looks like this:
while (you can run a piece of code and get back a value) {
do something
}
So each time around the loop, it executes the piece of code in the while
condition and expects to get a single value back. The code in the while
condition is run in scalar context.
A foreach
loop, on the other hand, only executes its code once and expects to get a list of values back. The code between parentheses at the start of the loop is executed in list context.
This is why you read a large file a line at a time using:
while (<$file_handle>) {
...
}
This only reads a single record from the file at a time. If you used a foreach
loop instead like this:
foreach (<$file_handle>) {
...
}
then you would get all of the records back from the filehandle at once - which, obviously, takes far more memory.
Dereferencing an array reference works like that too. You get all of the values back at the same time. The overridden method (next()
) will only be called once and will be expected to return a list of values.
I show some techniques in Object::Iterate. Give your object some methods to supply the next value and go from there.
[ This adds to Dave Cross's answer rather than being an answer on its own ]
Having a single iterator instance per collection cause all kinds of problem. That's why everyone uses keys
instead of each
, for example. As such, I strongly recommend that your class produces an iterator rather than being one itself, as the following does:
package My::Collection;
use strict;
use warnings;
use Iterator::Simple qw( iarray );
sub new {
my ($class) = @_;
my $self = bless({}, $class);
$self->{fields} = [];
return $self;
}
sub add {
my ($self, $elem) = @_;
push @{ $self->{fields} }, $elem;
}
sub iter {
my ($self) = @_;
return iarray($self->{fields});
}
1;
Use it as follows:
use strict;
use warnings;
use feature qw( say );
use My::Collection qw( );
my $collection = My::Collection->new();
$collection->add("Hi");
$collection->add("Hello");
$collection->add("Yeet");
my $iter = $collection->iter();
while ( my ($item) = $iter->next() ) {
say $item;
}
You can also use either of the following more magical options:
while ( my ($item) = $iter->() )
while ( my ($item) = <$iter> )