-
Iterator functions are now allowed to have a
close
argument. If they do, they will be called with aclose = 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 generatorfor
loops are now cleaned up when terminated early, either because of an error or because of abreak
(#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 theirpromises::promise()
invisibly (#46, @shikokuchuo). -
Fixes for CRAN checks.
- Internal fix for R-devel.
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 ofas.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()
andcollect()
. -
iterate()
has been renamed toloop()
to avoid name clash and semantic conflict withreticulate::iterate()
. -
collect()
callsas_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 likewithr::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 atryCatch()
). 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()
. Setoptions(coro_debug = TRUE)
for browsing all functions created with coro. Usecoro_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 fromyield()
. -
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:
- An iterator is a function. You advance it and get a new value by calling it.
- An iterator signals exhaustion by returning
exhausted()
(or equivalently, thequote(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