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

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-2015 by Joel Berger

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