Clojure 1.12.0-alpha1 (30 июня 2022)

Сегодня мы выпускаем Clojure 1.12.0-alpha1, и мы призываем вас попробовать его и дать нам свои отзывы!

Политика интернализации переменных

Интернализация var в пространстве имен (в отличие от алиасинга) должна создавать стабильную ссылку, которая никогда не будет перемещена, так что все ссылки на интернализированный var получают один и тот же объект. Были некоторые случаи, когда интернированные var могли быть перемещены, и в версии 1.12.0-alpha1 они были ужесточены. Если вы столкнетесь с такой ситуацией, вы увидите предупреждение типа “REJECTED: attempt to replace interned var #’some-ns/foo to #’other-ns/foo in some-ns, you must ns-unmap first”.

Это устраняет первопричину проблемы, возникшей в версии Clojure 1.11.0, которая добавила новые функции в clojure.core (в частности, abs). Скомпилированный код из более ранней версии Clojure с именами var, которые соответствовали новым добавленным функциям в clojure.core, был несвязан при загрузке в среду исполнения 1.11.0 (подробнее об этом в одной из будущих статей блога). В дополнение к CLJ-2711 мы откатили предыдущее исправление в этой области (CLJ-1604).

Эффективная очистка памяти и разбиение для персистентных или алгоритмических коллекций

Разбиение коллекции на разделы использует серию дублей (для построения раздела) и падений (для пропуска этого раздела). CLJ-2713 добавляет новый внутренний интерфейс (IDrop), указывающий на то, что коллекция может разбиваться более эффективно, чем при последовательном обходе, и реализует это для постоянных коллекций и алгоритмических коллекций, таких как range и repeat. Эти оптимизации используются в drop, nthrest и nthnext.

Кроме того, появились новые функции partitionv, partitionv-all и splitv-at, которые более эффективны, чем их существующие аналоги, и производят векторные разделы вместо реализованных seq-разделов.

Более подробную информацию вы можете прочитать в статье блога Efficient Partitioning.

Изменения в сериализации

CLJ-1327 явно устанавливает идентификатор сериализации Java для классов в Clojure, которые реализуют сериализацию Java. В Clojure 1.11.0 это изменилось для двух классов без необходимости, и мы отменили эти изменения в Clojure 1.11.1 - этим мы завершаем эту работу для остальных классов.

Типы данных Clojure реализуют интерфейсы сериализации Java, начиная с Clojure 1.0. Сериализация Java предназначена для сохранения графов экземпляров Java в поток байтов. Каждый класс имеет идентификатор (serialVersionUID), который автоматически генерируется на основе имени класса, иерархии типов и сериализуемых полей. Во время десериализации десериализация может произойти только в том случае, если доступный класс имеет идентификатор, совпадающий с идентификатором класса, записанным в сериализованных байтах.

Clojure никогда не давал гарантии согласованности сериализации в разных версиях Clojure, но мы не хотим нарушать совместимость больше, чем это необходимо, и эти изменения дадут нам больше контроля над этим в будущем.

Расширение empty? на counted? для коллекций, которые не являются sequable, например, transients.

CLJ-1872 добавляет поддержку counted? коллекций в empty?, которая ранее требовала, чтобы коллекции были seqable. Это и более эффективно для подсчитываемых коллекций, и empty? теперь будет работать для подсчитываемых, но неповторяемых коллекций (например, переходных).