https://clojure.org/news/2024/09/05/clojure-1-12-0 Clojure logo Clojure OverviewReferenceAPIReleasesGuidesCommunityDevNews [ ] [clojure.org ] [Search] Clojure 1.12.0 Clojure Deref (Aug 30, 2024) Clojure 1.12.0-rc2 Clojure Deref (Aug 23, 2024) Clojure Deref (Aug 16, 2024) Clojure Deref (Aug 9, 2024) Clojure 1.11.4 Clojure Deref (Aug 3, 2024) Clojure 1.12.0-rc1 Clojure Deref (July 27, 2024) Clojure Deref (July 17, 2024) Clojure Deref (July 5, 2024) Clojure Deref (June 28, 2024) Clojure 1.12.0-beta1 Clojure Deref (June 13, 2024) Clojure Deref (June 8, 2024) Clojure/conj 2024 CFP Clojure Deref (June 1, 2024) Clojure/conj 2024 Registration Clojure Deref (May 24, 2024) Clojure 1.12.0-alpha12 Clojure Deref (May 17, 2024) Clojure Deref (May 10, 2024) Clojure Deref (May 3, 2024) Clojure 1.12.0-alpha11 Clojure 1.12.0-alpha10 Clojure Deref (Apr 26, 2024) Clojure 1.11.3 Clojure Deref (Apr 19, 2024) Clojure Deref (Apr 12, 2024) Clojure Deref (Apr 5, 2024) Clojure Deref (Mar 29, 2024) Clojure Deref (Mar 22, 2024) Clojure Deref (Mar 15, 2024) Clojure Deref (Mar 8, 2024) Clojure 1.11.2 Clojure Deref (Mar 1, 2024) Clojure Deref (Feb 26, 2024) Clojure 1.12.0-alpha8 Clojure Deref (Feb 15, 2024) Clojure Deref (Feb 9, 2024) Clojure Conj 2024 Clojure 1.12.0-alpha6 Clojure 1.12.0-alpha7 Clojure Deref (Feb 2, 2024) Clojure Deref (Jan 26, 2024) Clojure Deref (Jan 19, 2024) Clojure Deref (Jan 12, 2024) Clojure Deref (Jan 7, 2024) Clojure Deref (Dec 22, 2023) Clojure Deref (Dec 15, 2023) Clojure Deref (Dec 8, 2023) Clojure Deref (Dec 1, 2023) Clojure Deref (Nov 24, 2023) Clojure Deref (Nov 17, 2023) Clojure Deref (Nov 10, 2023) Clojure Deref (Nov 3, 2023) Clojure Deref (Oct 27, 2023) Clojure Deref (Oct 23, 2023) Clojure 1.12.0-alpha5 Clojure Deref (Oct 16, 2023) Clojure Deref (Oct 6, 2023) Clojure Deref (Sept 29, 2023) Clojure Deref (Sept 22, 2023) Clojure Deref (Sept 15, 2023) Clojure Deref (Sept 8, 2023) Clojure Deref (Sept 1, 2023) Clojure Deref (Aug 25, 2023) Clojure Deref (Aug 18, 2023) Clojure Deref (Aug 11, 2023) Clojure Deref (Aug 6, 2023) (next Rich) Clojure Deref (July 28, 2023) Clojure Deref (July 20, 2023) Clojure Deref (July 7, 2023) Clojure Deref (June 30, 2023) State of Clojure 2023 Results Clojure Deref (June 23, 2023) Clojure Deref (June 16, 2023) Clojure Deref (June 9, 2023) Clojure Deref (June 2, 2023) Clojure Deref (May 26, 2023) Clojure Deref (May 19, 2023) Clojure Deref (May 12, 2023) Clojure Deref (May 5, 2023) Clojure Deref (May 1, 2023) Introducing Morse Clojure Deref (Apr 21, 2023) Clojure Deref (Apr 14, 2023) Clojure 1.12.0-alpha2 Clojure Deref (Apr 10, 2023) Clojure Deref (Mar 31, 2023) Clojure Deref (Mar 27, 2023) Clojure Deref (Mar 18, 2023) Clojure Deref (Mar 10, 2023) Clojure Deref (Mar 3, 2023) State of Clojure 2023 Survey Clojure Deref (Feb 26, 2023) Clojure Deref (Feb 17, 2023) Clojure Deref (Feb 10, 2023) Clojure Deref (Feb 3, 2023) Clojure Deref (Jan 30, 2023) Clojure Deref (Jan 20, 2023) Clojure Deref (Jan 13, 2023) Clojure Deref (Jan 6, 2023) Clojure Deref (Dec 22, 2022) Clojure Deref (Dec 16, 2022) Clojure Deref (Dec 8, 2022) Clojure Deref (Dec 2, 2022) Clojure Deref (Nov 23, 2022) Clojure Deref (Nov 18, 2022) Clojure Deref (Nov 11, 2022) Clojure Deref (Nov 4, 2022) Clojure Deref (Oct 28, 2022) Clojure Deref (Oct 21, 2022) Clojure Deref (Oct 14, 2022) Clojure Deref (Oct 10, 2022) Clojure Deref (Oct 3, 2022) Clojure Deref (Sep 26, 2022) Clojure Deref (Sep 16, 2022) Clojure Deref (Sep 9, 2022) Clojure Deref (Sep 2, 2022) Clojure Deref (Aug 26, 2022) Clojure Deref (Aug 19, 2022) Clojure Deref (Aug 12, 2022) Clojure Deref (Aug 5, 2022) Clojure Deref (July 30, 2022) Clojure Deref (July 15, 2022) Clojure Deref (July 8, 2022) Clojure Deref (July 1, 2022) Clojure 1.12.0-alpha1 Clojure Deref (June 24, 2022) Clojure Deref (June 17, 2022) Clojure Deref (June 10, 2022) State of Clojure 2022 Results Clojure Deref (June 2, 2022) Clojure Deref (May 27, 2022) Clojure Deref (May 20, 2022) Clojure Deref (May 13, 2022) Clojure Deref (May 6, 2022) Clojure Deref (Apr 29, 2022) Clojure Deref (Apr 22, 2022) Clojure Deref (Apr 14, 2022) Clojure Deref (Apr 8, 2022) Clojure 1.11.1 release Clojure Deref (Apr 1, 2022) Clojure Deref (Mar 25, 2022) Clojure 1.11.0 release Clojure Deref (Mar 20, 2022) Clojure Deref (Mar 11, 2022) Clojure Deref (Mar 4, 2022) Clojure Deref (Feb 28, 2022) State of Clojure 2022 Survey Clojure Deref (Feb 18, 2022) Clojure Deref (Feb 14, 2022) Clojure Deref (Feb 4, 2022) Clojure Deref (Jan 28, 2022) Clojure Deref (Jan 21, 2022) Clojure Deref (Jan 14, 2022) Clojure Deref (Jan 7, 2022) Clojure Deref (Dec 23, 2021) Clojure Deref (Dec 17, 2021) Clojure Deref (Dec 10, 2021) Clojure Deref (Dec 2, 2021) Clojure Deref (Nov 24, 2021) Clojure Deref (Nov 19, 2021) Clojure Deref (Nov 12, 2021) Clojure Deref (Nov 5, 2021) Clojure Deref (Oct 29, 2021) Clojure Deref (Oct 22, 2021) Clojure Deref (Oct 14, 2021) Clojure Deref (Oct 8, 2021) Clojure Deref (Sept 24, 2021) Clojure Deref (Sept 17, 2021) Clojure Deref (Sept 10, 2021) Clojure Deref (Sept 3, 2021) Clojure Deref (Aug 27, 2021) Clojure Deref (Aug 20, 2021) Clojure Deref (Aug 13, 2021) Clojure Deref (July 30, 2021) Clojure Deref (July 23, 2021) Clojure Deref (July 16, 2021) Source Libs and Builds Clojure Deref (July 9, 2021) Clojure Deref (July 2, 2021) Clojure Deref (June 25, 2021) Clojure Deref (June 18, 2021) Clojure Deref (June 11, 2021) Clojure Deref (June 4, 2021) State of Clojure 2021 Results Keyword argument functions now also accept maps Clojure 1.10.3 release Clojure 1.10.2 release State of Clojure 2021 Survey Cognitect Joins Nubank! Clojure Homebrew Tap State of Clojure 2020 Results State of Clojure 2020 Survey Clojure Forum Clojure 1.10.1 release JIRA Migration State of Clojure 2019 Results State of Clojure 2019 Survey Clojure 1.10 release State of Clojure 2018 Results Git Deps for Clojure Clojure 1.9 is now available State of Clojure 2016 Results Introducing clojure.spec State of Clojure 2015 survey results Clojure 1.8 is now available Welcome to the new clojure.org! Clojure 1.7 is now available Transducers are Coming Clojure core.async Channels Anatomy of a Reducer Reducers - A Library and Model for Collection Processing Clojure Governance and How It Got That Way Introducing ClojureScript Clojure 1.12.0 Clojure 1.12.0 05 September 2024 Alex Miller Clojure 1.12.0 is now available! Find download and usage information on the Downloads page. 1 Compatibility 1.1 Java 8 - Compatiblity EOL notice Clojure 1.12 produces Java 8 bytecode (same as Clojure 1.10 and 1.11), but this is expected to be the last release using a Java 8 baseline. Future releases will move the bytecode and minimum Java compatibility to a newer Java LTS release. 1.2 Java 21 - Virtual thread pinning from user code under synchronized Clojure users want to use virtual threads on JDK 21. Prior to 1.12, Clojure lazy-seqs and delays, in order to enforce run-once behavior, ran user code under synchronized blocks, which as of JDK 21 don't yet participate in cooperative blocking. Thus if that code did e.g. blocking I/O it would pin a real thread. JDK 21 may emit warnings for this when using -Djdk.tracePinnedThreads=full. To avoid this pinning, in 1.12 lazy-seq and delay use locks instead of synchronized blocks. 1.3 Security Fix CVE-2024-22871 detailed in GHSA-vr64-r9qj-h27f: 1.4 Serialization CLJ-1327 explicitly sets the Java serialization identifier for the classes in Clojure that implement Java serialization. In Clojure 1.11.0 this changed for two classes unnecessarily and we reverted those changes in Clojure 1.11.1 - this completes that work for the rest of the classes. Clojure data types have implemented the Java serialization interfaces since Clojure 1.0. Java serialization is designed to save graphs of Java instances into a byte stream. Every class has an identifier (the serialVersionUID) that is automatically generated based on the class name, it's type hierarchy, and the serialized fields. At deserialization time, deserialization can only occur when the available class has an identifier that matches the class id recorded in the serialized bytes. Clojure has never provided a guarantee of serialization consistency across Clojure versions, but we do not wish to break compatibility any more than necessary and these changes will give us more control over that in the future. 1.5 Dependencies Updated dependencies: * spec.alpha dependency to 0.5.238 - changes * core.specs.alpha dependency to 0.4.74 - changes 2 Features 2.1 Add libraries for interactive use There are many development-time cases where it would be useful to add a library interactively without restarting the JVM - speculative evaluation, adding a known dependency to your project, or adding a library to accomplish a specific task. Clojure now provides new functions to add libraries interactively, without restarting the JVM or losing the state of your work: * add-lib takes a lib that is not available on the classpath, and makes it available by downloading (if necessary) and adding to the classloader. Libs already on the classpath are not updated. If the coordinate is not provided, the newest Maven or git (if the library has an inferred git repo name) version or tag are used. * add-libs is like add-lib, but resolves a set of new libraries and versions together. * sync-deps calls add-libs with any libs present in deps.edn, but not yet present on the classpath. These new functions are intended only for development-time interactive use at the repl - using a deps.edn is still the proper way to build and maintain production code. To this end, these functions all check that *repl* is bound to true (that flag is bound automatically by clojure.main/repl). In a clojure.main REPL, these new functions are automatically referred in the user namespace. In other repls, you may need to (require '[clojure.repl.deps :refer :all]) before use. Library resolution and download are provided by tools.deps. However, you do not want to add tools.deps and its many dependencies to your project classpath during development, and thus we have also added a new api for invoking functions out of process via the Clojure CLI. 2.2 Invoke tool functions out of process There are many useful tools you can use at development time, but which are not part of your project's actual dependencies. The Clojure CLI provides explicit support for tools with their own classpath, but there was not previously a way to invoke these interactively. Clojure now includes clojure.tools.deps.interop/invoke-tool to invoke a tool function out of process. The classpath for the tool is defined in deps.edn and you do not need to add the tool's dependencies to your project classpath. add-lib functionality is built using invoke-tool but you can also use it to build or invoke your own tools for interactive use. Find more about the function execution protocol on the CLI reference. 2.3 Start and control external processes For a long time, we've had the clojure.java.shell namespace, but over time Java has provided new APIs for process info, process control, and I/O redirection. This release adds a new namespace clojure.java.process that takes advantage of these APIs and is easier to use. See: * start - full control over streams with access to the underlying Java objects for advanced usage * exec - covers the common case of executing an external process and returning its stdout on completion 2.4 Method values Clojure programmers often want to use Java methods in higher-order functions (e.g. passing a Java method to map). Until now, programmers have had to manually wrap methods in functions. This is verbose, and might require manual hinting for overload disambiguation, or incur incidental reflection or boxing. Programmers can now use qualified methods as ordinary functions in value contexts - the compiler will automatically generate the wrapping function. The compiler will generate a reflective call when a qualified method does not resolve due to overloading. Developers can supply :param-tags metadata on qualified methods to specify the signature of a single desired method, 'resolving' it. 2.5 Qualified methods - Class/method, Class/.method, and Class/new Java members inherently exist in a class. For method values we need a way to explicitly specify the class of an instance method because there is no possibility for inference. Qualified methods have value semantics when used in non-invocation positions: * Classname/method - value is a Clojure function that invokes a static method * Classname/.method - value is a Clojure function that invokes an instance method * Classname/new - value is a Clojure function that invokes a constructor Note: developers must use Classname/method and Classname/.method syntax to differentiate between static and instance methods. Qualified method invocations with :param-tags use only the tags to resolve the method. Without param-tags they behave like the equivalent dot syntax, except the qualifying class takes precedence over hints of the target object, and over its runtime type when invoked via reflection. Note: Static fields are values and should be referenced without parens unless they are intended as function calls, e.g (System/out) should be System/out. Future Clojure releases will treat the field's value as something invokable and invoke it. 2.6 :param-tags metadata When used as values, qualified methods supply only the class and method name, and thus cannot resolve overloaded methods. Developers can supply :param-tags metadata on qualified methods to specify the signature of a single desired method, 'resolving' it. The :param-tags metadata is a vector of zero or more tags: [tag ... ]. A tag is any existing valid :tag metadata value. Each tag corresponds to a parameter in the desired signature (arity should match the number of tags). Parameters with non-overloaded types can use the placeholder _ in lieu of the tag. When you supply :param-tags metadata on a qualified method, the metadata must allow the compiler to resolve it to a single method at compile time. A new metadata reader syntax ^[tag ... ] attaches :param-tags metadata to member symbols, just as ^tag attaches :tag metadata to a symbol. 2.7 Array class syntax Clojure supports symbols naming classes both as a value (for class object) and as a type hint, but has not provided syntax for array classes other than strings. Developers can now refer to an array class using a symbol of the form ComponentClass/#dimensions, eg String/2 refers to the class of a 2 dimensional array of Strings. Component classes can be fully-qualified classes, imported classes, or primitives. Array class syntax can be used as both type hints and values. Examples: String/1, java.lang.String/1, long/2. 2.8 Functional interfaces Java programs emulate functions with Java functional interfaces (marked with the @FunctionalInterface annotation), which have a single method. Clojure developers can now invoke Java methods taking functional interfaces by passing functions with matching arity. The Clojure compiler implicitly converts Clojure functions to the required functional interface by constructing a lambda adapter. You can explicitly coerce a Clojure function to a functional interface by hinting the binding name in a let binding, e.g. to avoid repeated adapter construction in a loop, e.g. (let [^ java.util.function.Predicate p even?] ... ). 2.9 Java Supplier interop Calling methods that take a Supplier (a method that supplies a value) had required writing an adapter with reify. Clojure has a "value supplier" interface with semantic support already - IDeref. All IDeref impls (delay, future, atom, etc) now implement the Supplier interface directly. 2.10 Streams with seq, into, reduce, and transduce support Java APIs increasingly return Streams and are hard to consume because they do not implement interfaces that Clojure already supports, and hard to interop with because Clojure doesn't directly implement Java functional interfaces. In addition to functional interface support, Clojure now provides these functions to interoperate with streams in an idiomatic manner, all functions behave analogously to their Clojure counterparts: * (stream-seq! stream) = seq * (stream-reduce! f [init-val] stream) = val * (stream-transduce! xf f [init-val] stream) = val * (stream-into! to-coll [xf] stream) = to-coll All of these operations are terminal stream operations (they consume the stream). 2.11 PersistentVector implements Spliterable Java collections implement streams via "spliterators", iterators that can be split for faster parallel traversal. PersistentVector now provides a custom spliterator that supports parallelism, with greatly improved performance. 2.12 Efficient drop and partition for persistent or algorithmic collections Partitioning of a collection uses a series of takes (to build a partition) and drops (to skip past that partition). CLJ-2713 adds a new internal interface (IDrop) indicating that a collection can drop more efficiently than sequential traversal, and implements that for persistent collections and algorithmic collections like range and repeat. These optimizations are used in drop, nthrest, and nthnext. Additionally, there are new functions partitionv, partitionv-all, and splitv-at that are more efficient than their existing counterparts and produce vector partitions instead of realized seq partitions. 2.13 Var interning policy Interning a var in a namespace (vs aliasing) must create a stable reference that is never displaced, so that all references to an interned var get the same object. There were some cases where interned vars could get displaced and those have been tightened up in 1.12.0-alpha1. If you encounter this situation, you'll see a warning like "REJECTED: attempt to replace interned var #'some-ns/foo with # 'other-ns/foo in some-ns, you must ns-unmap first". This addresses the root cause of an issue encountered with Clojure 1.11.0, which added new functions to clojure.core (particularly abs). Compiled code from an earlier version of Clojure with var names that matched the newly added functions in clojure.core would be unbound when loaded in a 1.11.0 runtime. In addition to CLJ-2711, we rolled back a previous fix in this area (CLJ-1604). Detailed changelog See the official changelog for a complete list of all changes in 1.12.0. Contributors Thanks to all the community members who contributed patches to Clojure 1.12: * Ambrose Bonnaire-Sergeant * Christophe Grand * Frank Yin * Nicola Mometto * Ray McDermott * Steve Miner Community Resources Contributing Companies Site Legal License Privacy Policy Documentation Overview Reference API Guides Libraries & Tools Updates News Events ETC ClojureTV Books Swag Code Releases Source ClojureScript ClojureCLR Copyright 2008-2022 Rich Hickey | Privacy Policy Logo & site design by Tom Hickey Published 2024-09-05 Update this page