Releases: purescript-contrib/purescript-aff
v4.1.1
- Fixes bhead is not a functionFFI errors when yielding a fork at the tail of a fresh attempt context (possibly throughbracketacquisition 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 ParAffcancellation.
v4.0.0
This release (v4.0.0) features a revamped API for writing more expressive asynchronous programs with stronger guarantees.
- Fibercooperative multi-tasking primitive for fork/join workflows.
- Stronger cleanup guarantees with bracketandsupervise.
- Reformulated AVarsemantics
- Rewritten core with an emphasis on performance and consistency.
New Features and Enhancements
Fiber
Previously, Affs 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). Fibers 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. Fibers 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 resourceIn 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 Fibers 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 Fibers and clean them up and run their finalizers once the computation completes or is cancelled.
example = supervise do
  _ <- forkAff requestA
  _ <- forkAff requestB
  requestCIn 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 Affeffects via the FFI, you should transition to usingControl.Monad.Aff.Compat, which provides anEffFnadapter. This makes it easy to use idiomatic JavaScript callbacks when buildingAffactions.
- The AVarAPI methods have changed to match Haskell'sMVarAPI.putVarnow blocks until theAVaractually assimilates the value. Previously,putVarwould 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 usetryPutVarwhich will attempt a synchronous put.
- Argument order for AVarandFiberoperations consistently put the subject last.
- Several unlawful instances where removed for Aff(Alternative,MonadPlus, andMonadZero).
- forkAffnow returns a- Fiberrather than a- Canceler.
- forkAllwas removed. Just use- Traversableand- forkAffdirectly.
- cancelwas removed. Use- killFiber.
- The signature of makeAffhas changed to provide a single callback which takes anEither Error aargument.Cancelers are also required. If you are sure you have no means of cancelling an action, you can usenonCancelerormempty.
- Cancelers no longer yield- Boolean. This was meaningless and not useful, so all cancellation effects now yield- Unit.
- ParAffis no longer a newtype. Parallel computations should be constructed via- Control.Parallelwith- paralleland- sequential.
v4.0.0-rc.6
- Rename atomicallytoinvincible.
- Killing a suspended fiber should be synchronous.
v4.0.0-rc.5
- Changed the argument order of AVaroperations to have the AVar last.
v4.0.0-rc.4
- Reexport things in Control.Monad.Eff.Exceptionrelevant to theAffAPI.
v4.0.0-rc.3
- killalways succeeds. If a finalizer throws, it will rethrow in a fresh stack.
- Fixes the behavior of throwErrorandgeneralBracketwithin a finalizer.
v4.0.0-rc.2
- Fixes ParAffAltbehavior when propagating exceptions.