This question is in the same ballpark as this other on making blocks iterable, but seems to reveal a different problem with mixins (or a different misunderstanding of the syntax on my part). What Iterable
does is to make a data structure effectively iterable, that is, you can create loops by preceding it with for
.
Iterable serves as an API for objects that can be iterated with the for construct and related iteration constructs, like hyper operators.
So let's try to put this to practice:
my &logger = -> $event {
state %store;
if ( $event ) {
%store{ DateTime.new( now ) } = $event;
} else {
%store;
}
}
role Forable does Iterable {
method iterator(&self:) {
self( Nil );
}
}
logger( "One" );
logger( "Two" );
&logger does Forable;
.say for &logger;
This simply does not work; say
is applied to &logger
as a simple item. However, it works if we change that last sentence to:
.say for &logger.iterator;
Which I guess that indicates that the role is actually working, and mixed in. Since the type for &logger
is Block+{Forable}
, maybe it does not work if Iterable is not mixed in directly. In fact, erasing does Iterable
from the Forable
declaration does not affect it in any way. Let's try then this:
&logger does (Iterable,Forable);
Now the type of &logger
is revealed as Block+{Iterable,Forable}
, but still no joy. iterator
has to be called directly. Any idea on how to solve this?
As I understand, if the (single) argument to an iterating feature is a
Scalar
container, then it uses the value in the container and does not call.iterator
. Otherwise, it calls.iterator
on it, evaluating it first if it's an expression or routine call.The
&
is a noun marker (sigil) marking aCallable
that is inherently a single thing, a single block of code.More specifically,
&logger
is bound to aScalar
container whose type isCallable
, exactly the same as$logger
(with a$
sigil) would be if you wrotemy Callable $logger
:displays:
That's actually the type of the
Callable
that's contained in theScalar
container that's bound to&logger
.It's not the type of the
&logger
container itself, which is aScalar
, as shown above.When given a single argument in the form of a variable, iterating features like
for
look at the variable, not the value contained in the variable, to see if it'sIterable
. AScalar
is notIterable
.See lizmat's answer for one approach.
I don't think you can. The basic problem is that
&foo
(theCallable
object) andfoo()
(calling theCallable
object) are two very different things.Feels to me you're trying to add a
method
to aclass
, but you're working with aSub
.You need to mixin the
iterator
method on the return value oflogger
. As I don't really understand what you're trying to achieve, it's hard to answer the question.Looking at the result that you apparently want to achieve, I came up with this:
But that doesn't use
role
s at all. So that may not be what you're going for.