NAME
Generator::Object - Generator objects for Perl using Coro
SYNOPSIS
use strict; use warnings;
use Generator::Object;
my $gen = generator {
my $x = 0;
while (1) {
$x += 2;
$_->yield($x);
}
};
print $gen->next; # 2
print $gen->next; # 4
DESCRIPTION
Generator::Object provides a class for creating Python-like generators for Perl using Coro
. Calling the next
method will invoke the generator, while inside the generator body, calling the yield
method on the object will suspend the interpreter and return execution to the main thread. When next
is called again the execution will return to the point of the yield
inside the generator body. Arguments passed to yield
are returned from next
. This pattern allows for long-running processes to return values, possibly forever, with lazy evaluation.
For convenience the generator object is provided to the function body as $_
. Further the context of the next
method call is provided via the wantarray
object method. When/if the generator is exhausted, the next
method will return undef
and the exhausted
method will return true. Any return value from the body will then be available from the retval
method. The generator may be restarted at any time by using the restart
method. retval
will be empty after the generator restarts.
Note: in version 0.01 of this module the generator would automatically restart when calling next
again after it was exhausted. This behavior was removed in version 0.02 because upon reflection this is not usually what the author means and since restart
is available it can be done manually.
The internals of the object are entirely off-limits and where possible they have been hidden to prevent access. No subclass api is presented nor planned. The use of Coro internally shouldn't interfere with use of Coro externally.
EXPORTS
generator
my $gen = generator { ...; $_->yield($val) while 1 };
Convenience function for creating instances of Generator::Object. Takes a block (subref) which is the body of the generator. Returns an instance of Generator::Object.
CONSTRUCTOR
new
my $gen = Generator::Object->new(sub{...; $_->yield});
Takes a subref which is the body of the generator. Returns an instance of Generator::Object.
METHODS
exhausted
while (1) {
next if defined $gen->next;
print "Done\n" if $gen->exhausted;
}
When the generator is exhausted the next
method will return undef
. However, since next
might legitimately return undef
, this method is provided to check that the generator has indeed been exhausted. If the generator is restarted, then this method will again returns false.
next
my $first = $gen->next;
my $second = $gen->next;
This method iterates the generator until yield
is called or the body is returned from. It returns any value passed to yield
, in list context all arguments are returned, in scalar context the first argument is returned. The context of the next
call is available from the wantarray
method for more manual control.
When the generator is exhausted, that is to say, when the body function returns, next
returns undef
. Check exhausted
to differentiate between exhaustion and a yielded undef
. Any values returned from the body are available via the retval
method, again list return is emulated and the wantarray
method (of the final next
call) can be checked when returning.
restart
my $gen = generator { my $x = 1; $_->yield($x++) while 1 };
my $first = $gen->next;
$gen->restart;
$first == $gen->next; # true
Restarts the generator to its initial state. Of course if your generator has made external changes, those will remain. Any values in retval
are cleared and exhausted
is reset (if applicable).
Note: restart
is no longer implicitly called when next
is invoked on an exhasted generator. You may recreate the old behavior by simply doing
$gen->restart if $gen->exhausted;
retval
my $gen = generator { return 'val' };
$gen->next;
my $val = $gen->retval; # 'val'
Returns the value or values returned from the generator upon exhaustion if any. In list context all returned values are given, in scalar context the first element is returned. Note that the context in which next
was called as the generator is exhausted is available via the wantarray
method for manual control.
Before the generator is exhausted (and therefore before it has really returned anything) the value of retval is undef
in scalar context and an empty list in list context. Note that version 0.01 returned undef
in both contexts but this has been corrected in version 0.02.
wantarray
my $gen = generator {
while (1) {
$_->wantarray
? $_->yield('next called in list context')
: $_->yield('next called in scalar context');
}
}
my ($list) = $gen->next;
my $scalar = $gen->next;
Much like the Perl built-in of the same name, this method provides the context in which the next
method is called, making that information available to the generator body.
yield
my $gen = generator { ...; $_->yield($val) while 1 };
This method is the guts of the generator. When called yield
suspends the state of the interpreter as it exists inside the generator body and returns to the point at which next
was called. The values passed will be returned by next
(see its documentation for more).
This method should not be called outside the generator body. For now, doing so dies. In the future though this might change to be a safer no-op in the future, or else the method may only be made available inside the body as safe-guards. In the meantime, just don't do it!
FUTURE WORK
I intend (possibly soon) to allow arguments to be passed to the generator body possibly even on every call to next
. Stay tuned.
SEE ALSO
A few similar modules already exist. Their API and design choices weren't to my liking, but they may appeal to you. Certainly I used them as reference and thanks are due.
SOURCE REPOSITORY
http://github.com/jberger/Generator-Object
AUTHOR
Joel Berger, <joel.a.berger@gmail.com>
COPYRIGHT AND LICENSE
Copyright (C) 2013-2015 by Joel Berger
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.