The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

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. After the generator has reported that it is exhausted, another call to next will implicitly restart the generator. The generator may be restarted at any time by using the restart method. retval will be empty after the generator restarts.

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.

Note that if next is called on an exhausted generator, it is restarted, and thus exhausted will again return a false value.

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. This emulates returning a list. 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).

restart is implicitly called when next is invoked on an exhasted generator.

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. This emulates returning a list. Note that the context in which next was called as the generator is exhausted is available via the wantarray method for manual control.

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

Coro

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.

Coro::Generator
Attribute::Generator

SOURCE REPOSITORY

http://github.com/jberger/Generator-Object

AUTHOR

Joel Berger, <joel.a.berger@gmail.com>

COPYRIGHT AND LICENSE

Copyright (C) 2013 by Joel Berger

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

1;