Again, I'm not sure I totally buy it, but it's an interesting idea.
Consider this (thoroughly untested) code:
sub add_stuff_to_file {
my ($filehandle, $stuff) = @_;
($stuff->isa('Iterable')) || die "Stuff must be iterable";
my $i = $stuff->iterator();
($i->isa('Iterator')) || die "Stuff's iterator must be an Iterator
+";
while ($i->hasNext()) {
print $filehandle $i->next();
}
}
Now, consider the following code which uses it.
serialize_stuff_to_file(Array::Iterator->new(@array));
serialize_stuff_to_file(ArrayOfArrays::Iterator->new(@array));
serialize_stuff_to_file(ArrayOfHashes::Iterator->new(@array));
serialize_stuff_to_file(Hash::Iterator->new(%hash));
serialize_stuff_to_file(HashOfHashes::Iterator->new(%hash));
serialize_stuff_to_file(HashOfArrays::Iterator->new(%hash));
serialize_stuff_to_file(Tree::Iterator->new($tree));
Since I know the Iterator will always respond to the same methods, and always produce the expected result on each loop, I can ignore the underlying structure of the object being iterated over. IMO, this is where MJD's argument that
foreach is an iterator breaks down.