Iterator functions are now allowed to have a close
argument.
If they do, they will be called with a close = TRUE
value
when iteration is terminated early. This gives the opportunity
to clean up resources.
Generators now run on.exit()
expressions when they are closed.
Iterators managed by coro::loop()
and by generator for
loops
are now cleaned up when terminated early, either because of an
error or because of a break
(#52).
Implicit and explicit return values of generators are no longer yielded. This is consistent with Javascript and Python and simplifies certain idioms (#51).
Generators and async functions assigned in namespaces no longer produce R CMD check notes about visible bindings (#40).
Async functions created by coro::async()
now return their
promises::promise()
invisibly (#46, @shikokuchuo).
Fixes for CRAN checks.
coro::as_iterator()
method added for reticulate Python objects,
enabling usage like: coro::loop(for (elem in my_py_object) ...)
(#37, @t-kalinowski).The exhaustion sentinel is now as.symbol(".__exhausted__.")
instead of as.symbol("exhausted")
to reduce the risk of
collisions. It is also recommended to never store the exhaustion
sentinel in an environment or list, and instead use it as a
temporary value to further reduce the risk of collisions (#35).
Fixed a leak that occurred via JIT caching (#36).
collect()
now preserves lists and data frames (#32).This is the first public version of coro.
Python iterators created with the reticulate package can now be
composed with coro generators. They can also be used with loop()
and collect()
.
iterate()
has been renamed to loop()
to avoid name clash and
semantic conflict with reticulate::iterate()
.
collect()
calls as_iterator()
on its input.
as_iterator()
is now a generic function (#28).
Generators and async functions now support on.exit()
expressions. They also support exit expressions installed with
functions like withr::local_options()
. This requires R >= 3.5.
Generator arguments are forced on reentry in the approriate context
(e.g. in the tryCatch()
context if generator was yielded from a
tryCatch()
). This makes it possible to clean up cancelled
generators (by jumping from the generator with a restart) or
propagate errors in async functions.
Generators and async functions now support yielding within
tryCatch()
expressions.
Generators and async functions are now disabled when an unexpected exit occurs (error, interrupt, restart invokation, debugger exit, etc.). Reentering the generator is an error.
Generators and async functions now support stepping with
browser()
. Set options(coro_debug = TRUE)
for browsing all
functions created with coro. Use coro_debug()
for browsing
specific functions.
generator()
now accepts functions of one argument. The first time
a generator is called the argument is defined in the suspendable
function. On subsequent invokations, the argument is returned from
yield()
.
generator()
now creates generator factories. It takes a function
template and returns a function that creates generator functions
from this template. This is consistent with languages like
Javascript and Python.
The async()
function operator creates functions for cooperative
concurrency using the later and promises framework.
async_generator()
creates iterable functions that are also
awaitable.
The iterator abstraction has been removed from coro. It is replaced with the following protocol:
exhausted()
(or
equivalently, the quote(exhausted)
symbol).Exhausted generators no longer throw when called again. Instead,
they return the exhausted()
sentinel (#6).
Fixed top-level break
statements in loops (#7).
Initial release