All notable changes to this project are documented here.
The format follows Keep a Changelog, and the project uses Semantic Versioning.
From 4.0.0 on this file is written by release-please out of the commit messages. What sits on the default branch but is not on Clojars yet stands in the open release pull request, not here. The per-version documentation lives on cljdoc.
An exception now travels as itself
(3dc5a80).
Up to 3.x everything that was not already an ExceptionInfo was converted
into one carrying {:code :unknown}, with the original as its cause. A
RuntimeException or a plain js/Error is now carried and rethrown
unchanged — same class, same message, same ex-data.
What breaks: (catch ExceptionInfo e …) was the documented pattern and
no longer sees a foreign exception. It needs Exception on the JVM and
:default in ClojureScript. The break is a quiet one — the error does not
disappear, it climbs past the catch to the next one, or out of the
program. Anyone catching ExceptionInfo should go through their handlers
before upgrading.
(ex-data e) is nil for such an exception; the {:code …} convention
now only holds for what this library builds itself. This applies wherever
an error enters: go, go-loop, thread, thread-call, map, reduce,
cb->c and the promise interop.
A thrown value that is no exception at all — ClojureScript lets you
throw 42, and a promise may reject with anything — is still lifted into
an ExceptionInfo, now with the value under :error. Without that it
would arrive on the channel indistinguishable from a result.
Error is no longer caught on the JVM
(59c8a39).
A StackOverflowError or OutOfMemoryError used to become an ordinary
channel value, letting the program carry on as if it could. It now escapes
into core.async's thread, which closes the channel. Catching is
Exception in go, thread-call and cb->c. ClojureScript has no such
distinction.
exception? answers whether a value is a carried error, and that is now
anything throwable — a Throwable on the JVM, a js/Error in
ClojureScript. It used to accept ExceptionInfo only.
->exception hands anything throwable back untouched instead of making it
the cause of a fresh ExceptionInfo.
thread and thread-call were unusable and always threw an
ArityException: both passed a workload argument to
core.async/thread-call, which the pinned core.async 1.3.610 does not
accept. core.async is now 1.9.865, where it does.ClassCastException on the JVM.
(reject :bad) reached ex-info in the cause position, where Clojure
demands a Throwable. Affected promise-chan, p->c and cb->c. In
cb->c the outer handler swallowed it, so {:code :callback-error}
silently came out as {:code :callback-based-function-error}.awalk, and with it apostwalk and aprewalk, hung forever on a record.
The record branch never put anything onto the channel it then waited for.consume!, smap and areduce stopped at the first falsy value, so a
nil or false in the middle silently dropped everything after it.amap yielded nil instead of a vector as soon as one result was nil.map, and through it all and amap, waited forever on an empty
collection.:error in
the ex-data. This changes ClojureScript, where it used to sit under
ex-cause — on the JVM it could not be recovered at all. Both platforms now
behave the same.map with no channels yields (f) rather than waiting forever, so
(all []) is [] and (map + []) is 0. A deliberate deviation from
core.async/map.->exception. Public because the expansion of cb->c runs in the caller's
namespace.thread unusable. core.async
1.8.730 is the new minimum: older versions have no workload argument on
thread-call and answer every call with an ArityException. Both test
suites run against 1.9.865, including the two places that reach into
core.async internals — ManyToManyChannel from impl.channels behind
chan?, and the ioc rewriting <debug relies on.provided now, not compile-scope
dependencies. They are there for this project's own build and tests, but
no longer land on a consumer's classpath — every Clojure project brings
its own. core.async is the only compile-scope dependency left.lein ancient is declared as a plugin, so "what is outdated here?" has an
answer that does not depend on the asker's local setup.ASYNC_BOUNDARY marker (#5).cb->c and the promise interop pass an ExceptionInfo rejection through
unchanged instead of wrapping it again, so its message and ex-data
survive (#4).p->c no longer blocks the calling thread on the JVM (#3).thread and thread-call, with the error handling of go.<? — use <?!, which says how it relates to <! and <!!.<!!, <?!! and <p!!, plus
<?! for a value that may or may not be a channel.jtk-dvlp.async.Releases before 3.3.2 are not reconstructed here; see the git history and the tags.
Can you improve this documentation? These fine people already did:
Claude & github-actions[bot]Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |