Clojure 1.12.0-alpha1

Clojure 1.12.0-alpha1

30 June 2022
Alex Miller

Today we are releasing Clojure 1.12.0-alpha1 and we would encourage you to try it and give us your feedback!

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 addressses 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 (more details in a future blog post). In addition to CLJ-2711, we rolled back a previous fix in this area (CLJ-1604).

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.

You can read more detail in the Efficient Partitioning blog post.

Serialization changes

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.

Extend empty? to counted? colls that aren’t seqable, such as transients

CLJ-1872 adds support for counted? collections to empty?, which previously required colletions to be seqable. This is both more efficient for counted collections, and empty? will now work on counted but non-seqable collections (like transient collections).