[ANN] ClojureCLR 1.12.3-alpha6 The big news: Now supporting .NET 11 (preview) and the new runtime async capability. One can now do async/await programming in ClojureCLR as simply as is done in C#. Because this is a preview release, one needs to explicitly uninstall and reinstall (rather than update) and specify the version:
dotnet tool uninstall -g clojure.main
dotnet tool install -g clojure.main --version 1.12.3-alpha6
This version brings ClojureCLR up to date with ClojureJVM 1.12.4. When this goes to beta (soon), I'll update the version to match ClojureJVM.
Other changes in this release:
• A couple of fixes for errors/inconsistencies brought to light by the Clojure Test Suite project:
◦ clojure.core.Num now throws an Exception on non-numeric types -- this makes ClojureCLR match ClojureJVM on things like strings passed to arithmetic operators
◦ Transient persistent vectors now implement IFn.invoke(Object)
• Make gen-delegate produce clean delegates without a hidden Closure parameter. This improves interop with framework like http://ASP.NET Minimal API that use reflection on delegate parameters.
• Fix gen-class :main to work properly on .NET 9+. This enables AOT-compiled Clojure executables to "just work" -- no C# required. It worked under Framework previously, an oversight when AOT-compilation returned in .NET 9. Also, the main properly waits for completion if the main returns a Task (`async` entry point)
But the big news is:
• .NET 11 ( now in preview) added as a supported framework. If you are working in advance of .NET 11 release, you're set to go. This also enables the next item.
• Support for runtime async/await interop (.NET 11 preview)!
If you've been paying attention to updates on what's new in .NET 11 (now in preview, GA release scheduled for November this year), a major item is runtime support for async/await.
C# has supported the declaration of async methods that allow the use of the await operation on tasks going back for many .NET releases.
In .NET 10 and prior, this support was accomplished by the C# compiler doing some complicated rewriting of the method into a state machine.
(This is very similar to the rewriting done in core.aync, if that helps.)
The runtime support now available .NET 11 means that the compiler manipulation is no longer necessary; the runtime deals with suspending and resuming your method around a call to await on the fly.
Among other things: (1) this improves the performance of async/await code; and (2) we can leverage this to give easy access to async/await functionality in ClojureCLR code.
There is a new library to support async programming in ClojureCLR: clojure.clr.async.task.alpha. If you require this namespace, say with :as t, you can write code such as
(defn ^:async shout-it-out [infile outfile]
(let [content (t/await (File/ReadAllTextAsync infile CancellationToken/None))
capitalized (.ToUpper content)]
(t/await (File/WriteAllTextAsync ^String outfile capitalized CancellationToken/None))
"I'm done yelling."))
The ^:async tag marks the function shout-it-out as being async, meaning you can use t/await to define suspension points (places to yield control and wait for a subtask to complete); it also tags the method as returning a System.Threading.Tasks.Task<Object> value. The macro t/await marks suspension points at calls to asynchronous I/O methods.
I wrote a small blog post with more details at: https://dmiller.github.io/clojure-clr-next/general/2026/04/16/runtime-async.html
The ClojureCLR has details on the clojure.clr.async.task.alpha library in the wiki at: https://github.com/clojure/clojure-clr/wiki/Runtime-async
This library and the compiler support are experimental at this point and subject to change. Suggestions for improvements are welcome.
Many thanks to @jarvinenemil for doing the heavy lifting on the design and implementation of this capability.