Releases: purescript-contrib/purescript-aff
v4.1.1
- Fixes
bhead is not a function
FFI errors when yielding a fork at the tail of a fresh attempt context (possibly throughbracket
acquisition orcatchError
).
v4.1.0
v4.0.2
- Fix regression in ParAff Applicative behavior when an exception occurs.
v4.0.1
- Fixes JavaScript runtime error in
ParAff
cancellation.
v4.0.0
This release (v4.0.0) features a revamped API for writing more expressive asynchronous programs with stronger guarantees.
Fiber
cooperative multi-tasking primitive for fork/join workflows.- Stronger cleanup guarantees with
bracket
andsupervise
. - Reformulated
AVar
semantics - Rewritten core with an emphasis on performance and consistency.
New Features and Enhancements
Fiber
Previously, Aff
s supported forkAff
, but it was very difficult to get values back when forked computations completed. Libraries like purescript-aff-future
were written to overcome this limitation (though with limitations of their own). The semantics of purescript-aff-future
have been assimilated into Aff
through the Fiber
type without any of the previous limitaions (like lack of cancellation). Fiber
s make it easy to not only fork computations, but also share their results among many consumers with joinFiber
, which will wait until the Fiber
completes, or yield immediately if it has already resolved. If a Fiber
threw an exception, then the exception will be rethrown in the observer. Fiber
s additionally support cancellation (killFiber
) and finalizers for cleanup (bracket
).
bracket
When we kill/cancel a Fiber
, often times we need to make sure some resource gets released. bracket
lets you take control of the acquire/use/release resource cycle.
example =
bracket
(openFile myFile) -- Acquire a resource
(\file -> closeFile file) -- Release the resource
(\file -> appendFile "hello" file) -- Use the resource
In the example above, the runtime will always ensure the "release" effect will run even in the presence of cancellation. There is also generalBracket
, which lets you observe whether the primary action completed successfully, threw an exception, or was killed asynchronously and run different cleanup effects accordingly.
supervise
Sometimes we need to fork many Fiber
s for a task, but it's possible (often through cancellation) for these sub-tasks to leak. We've introduced a supervise
combinator which will automatically keep track of forked Fiber
s and clean them up and run their finalizers once the computation completes or is cancelled.
example = supervise do
_ <- forkAff requestA
_ <- forkAff requestB
requestC
In the above example, if requestA
or requestB
are still running when requestC
completes, they will be killed by the runtime and have their finalizers run.
suspendAff
As an alternative to forkAff
, which eagerly forks and runs a computations, we've introduced suspendAff
. This forks a computation but does not initiate it until a result is demanded via joinFiber
. Results are still memoized (as all Fiber
results are), but are just computed lazily.
Stack-safety
With the old callback approach, each bind resulted in more and more stack, and it was trivial to blow the stack unless you explicitly used tailRecM
. The Aff
interpreter now uses a constant amount of stack space, making tailRecM
unnecesary. This extends to ParAff
as well.
Uncaught exceptions
Previously, exceptions thrown in forked computations were completely swallowed. This made it extremely difficult to diagnose bugs. Now if a Fiber
has no observers and it throws an exception, the exception will always be rethrown in a fresh stack. This can be observed by things like window.onerror
or just by watching the console.
Breaking Changes
- The low-level callback representation is no longer relevant. If you've defined
Aff
effects via the FFI, you should transition to usingControl.Monad.Aff.Compat
, which provides anEffFn
adapter. This makes it easy to use idiomatic JavaScript callbacks when buildingAff
actions. - The
AVar
API methods have changed to match Haskell'sMVar
API.putVar
now blocks until theAVar
actually assimilates the value. Previously,putVar
would queue the value, but yield immediately. It's possible to recover similar behavior as the old API withforkAff (try (putVar value avar))
(though this should be considered mildly unsafe), or you can usetryPutVar
which will attempt a synchronous put. - Argument order for
AVar
andFiber
operations consistently put the subject last. - Several unlawful instances where removed for
Aff
(Alternative
,MonadPlus
, andMonadZero
). forkAff
now returns aFiber
rather than aCanceler
.forkAll
was removed. Just useTraversable
andforkAff
directly.cancel
was removed. UsekillFiber
.- The signature of
makeAff
has changed to provide a single callback which takes anEither Error a
argument.Canceler
s are also required. If you are sure you have no means of cancelling an action, you can usenonCanceler
ormempty
. Canceler
s no longer yieldBoolean
. This was meaningless and not useful, so all cancellation effects now yieldUnit
.ParAff
is no longer a newtype. Parallel computations should be constructed viaControl.Parallel
withparallel
andsequential
.
v4.0.0-rc.6
- Rename
atomically
toinvincible
. - Killing a suspended fiber should be synchronous.
v4.0.0-rc.5
- Changed the argument order of
AVar
operations to have the AVar last.
v4.0.0-rc.4
- Reexport things in
Control.Monad.Eff.Exception
relevant to theAff
API.
v4.0.0-rc.3
kill
always succeeds. If a finalizer throws, it will rethrow in a fresh stack.- Fixes the behavior of
throwError
andgeneralBracket
within a finalizer.
v4.0.0-rc.2
- Fixes
ParAff
Alt
behavior when propagating exceptions.