Suppose we have the following class composing the role Iterable
:
class Word-Char does Iterable {
has @.words;
method !pairize($item) {
return $item => $item.chars;
}
method iterator( Word-Char:D: ) {
@!words.map({self!pairize($_)}).rotor(1).iterator
}
}
I could assign the object to a Positional
variable during object construction and iterate over that variable:
my @words = Word-Char.new: words => <the sky is blue>;
.say for @words;
OUTPUT:
(the => 3)
(sky => 3)
(is => 2)
(blue => 4)
However, what if the object is being passed around? How do I make sure it's still iterable?:
my $w = Word-Char.new: words => <the sky is blue>;
sub f( $w ) {
.say for $w
}
f($w);
OUTPUT:
Word-Char.new(words => ["the", "sky", "is", "blue"])
Goal:
By using Iterable
, Iterator
or both, I would like, if possible, to be able to iterate over an instance object of the class implementing these roles anywhere. Right now I know that by assigning the instance object during the object construction to a Positional
variable, I can get the iterable items the class provide but this isn't what I want. Instead I want to pass the object itself and iterate over it wherever/whenever I deem it necessary.
When dealing with scalar values that do the iterator role, the simplest way to accomplish what you are attempting is to tell perl6 your scalar value is iterable. You can do that by postfixing it with []
. Your example then looks like this:
my $w = Word-Char.new: words => <the sky is blue>;
.say for $w[]
Another thing....
Your iteration code has a bug in that it doesn't reset itself before returning IterationEnd
. A quick fix looks like the following:
class Word-Char does Iterable does Iterator {
has @.words;
has Int $!index = 0;
method !pairize($item) {
return $item => $item.chars;
}
method iterator() {self}
method pull-one( --> Mu ) {
if $!index < @!words.elems {
my $item = @!words[$!index];
$!index += 1;
return self!pairize($item);
}
else {
$!index = 0;
return IterationEnd;
}
}
}
However, this means that you have to keep all of the iteration logic (and its attributes) with the main class. Another, way would be to use an anonymous class, instead of using self
:
class Word-Char does Iterable {
has @.words;
method !pairize($item) {
return $item => $item.chars;
}
method iterator() {
my @words = @!words;
class :: does Iterator {
has $.index is rw = 0;
method pull-one {
return IterationEnd if $!index >= @words.elems;
@words[$!index++];
}
}.new;
}
}
The advantage of the above is that you can keep your iteration logic cleaner and isolated from the rest of the object. You also don't need to worry about resetting state.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With