Сегодня ночью была выпущена новая версия языка Clojure — 1.3. Что нового в этой версии? Давайте рассмотрим основные изменения сделанные в этой версии (детальный список изменений можно найти в соответствующей ветке репозитория).
Расширенная поддержка примитивных типов
В предыдущих версиях, примитивные типы (long, double, etc.) поддерживались только для локальных арифметических операций и при объявлении полей deftype/defrecord, но не для аргументов функций и не для возвращаемых значений. Boxing выполнялся всегда, что часто приводило к ощутимым накладным расходам.
В новой версии примитивные типы поддерживаются в полной мере, что приводит к значительному увеличению производительности кода (в соответствующих тестах, в среднем в 3-5 раз). Соответственно изменилась работа с арифметическими выражениями — для примитивных типов будут использоваться стандартные операторы Java. Но при этом не будет происходит автоматического превращения в "Big*" типы при переполнении, как это происходило раньше — вместо этого будет брошено исключение. Если вам все-таки нужно автоматическая конвертация, то вы можете использовать операторы +', *', и т.д., хотя они и более медленные. Битовые операции теперь только поддерживаются для примитивных типов, и вся их поддержка для "Big*" была убрана из языка.
Для использования примитивных типов вам необходимо добавить соответствующие type hints, например:
(defn fib ^long [^long n] (if (<= n 1) 1 (+ (fib (dec n)) (fib (- n 2)))))
Более подробно обо всем этом на соответствующей странице JIRA.
Улучшения defrecord и deftype
В версии 1.3 были сделаны различные улучшения для работы с defrecord и deftype:
- новый синтаксис для чтения и записи — либо с метками (
#myns.MyRecord{:a 1, :b 2}— только для записей), либо позиционный (#myns.MyRecord[1 2]— для записей и типов); - автоматическая генерация функций для создания типов и записей:
myns/map->MyRecord(только для записей) иmyns/->MyRecord(для записей и типов).
Подробнее можно прочитать вот тут.
Reflection API
Введено новое пространство имен clojure.reflect, функции которого должны обеспечить более удобную и быструю работу с классами, методами и т.д. Подробнее об этом тут.
Модульный clojure-contrib
Начиная с версии 1.3, больше не существует монолитного набора библиотек известного как clojure-contrib — вместо этого, были созданы отдельные проекты для каждой из библиотек, что позволяет им развиваться и выпускаться независимо друг от друга. Полный список всех старых библиотек, и соответствующих им новых, можно найти на отдельной странице.
Множественные улучшения производительности
Кроме улучшений в части производительности, описанных выше, в новом релизе сделано множество изменений чтобы обеспечить более высокую скорость работы программ на Clojure:
- Более быстрый доступ к переменным;
- Ускорение загрузки
- Promises не используют блокировок (locks);
- Инлайнинг
nil?, битовых функций, математических операций, функцийmin&maxс разным числом аргументов; - и многое другое...
Прочее
Помимо новой функциональности описанной выше, а также различных исправлений ошибок, в новой версии реализованы новые вещи (перечислены не все):
- Некоторые вспомогательные пространства имен (
clojure.set,clojure.xml,clojure.zip) не загружаются при запуске; - Объявления сделанные с помощью
defболее не являются "динамическими" по умолчанию — вы должны использовать^:dynamicесли хотите иметь возможность использования ее вbinding; - Улучшенные сообщения об ошибках и исключениях;
- Можно вызвать
derefс указанием таймаута; - Функция
compвозвращаетidentityесли вызвана без параметров; - Возможность указания разных возвращаемых типов в объявлениях одной функции с разными количествами аргументов;
- Некоторые функции перемещены в другие пространства имен;
5 комментариев:
Скажите, а в Clojure всегда так относятся к обратной совместимости или только в этом релизе? Ну или может где-то на сайте проекта есть какие-то оговорки, ну например что до версии 2.0 мы гарантируем никакой обратной совместимости?
ну большая часть кода должна работать без изменений, самое большое что сломали - clojure-contrib, но это было запланировано
Отличный обзор! Спасибо!
Что-то с автоматическим расширением интегральных типов какая-то ерунда. Common Lisp вполне себе автоматически преобразует fixnum в bignum и обратно по результату операции. А внутри ещё и fixnum в unboxed машинный вид перегоняет для скорости.
я так понимаю, что оверхед слишком большной на JVM :-(
Отправить комментарий