Clojure имеет gen-class, reify, proxy, а также deftype и defrecord, чтобы определить новые типы данных типа. Для языка, который оценивает синтаксическую простоту и терпит ненужную сложность, это кажется аберрацией. Может ли кто-нибудь объяснить, почему это так? Может ли общий Lisp -строчный defclass достаточно?
Почему Clojure имеет 5 способов определить класс вместо одного?
Ответ 1
Это сочетание трех разных факторов:
- Конкретная система типов jvm
- Необходимость немного отличающейся семантики для разных случаев использования при определении типов
- Тот факт, что некоторые из них были разработаны ранее, а некоторые позже, когда язык развился.
Итак, сначала рассмотрим, что они делают. deftype и gen-class похожи друг на друга, поскольку оба они определяют именованный класс для компиляции вовремя. На первом месте появился класс Gen, за которым следует deftype в clojure 1.2. Deftype является предпочтительным и имеет лучшие характеристики производительности, но более ограничительный. Класс deftype может соответствовать интерфейсу, но не может наследовать от другого класса.
Reify и прокси используются для динамического создания экземпляра анонимного класса во время выполнения. Сначала был прокси-сервер, reify - с deftype и defrecord в clojure 1.2. Reify предпочтительнее, так же как и deftype, где семантика не является слишком ограничительной.
Это оставляет вопрос о том, почему и ложь, и defrecord, поскольку они появились в одно и то же время, и имеют аналогичную роль. Для большинства целей мы хотим использовать defrecord: у него есть всякая доброта clojure, которую мы знаем и любим, секвенируем и так далее. Deftype предназначен для использования в качестве низкоуровневого строительного блока для реализации других структур данных. Он не включает обычные интерфейсы clojure, но у него есть опция изменяемых полей (хотя это не значение по умолчанию).
Для дальнейшего чтения:
Ответ 2
Короткий ответ заключается в том, что все они имеют разные и полезные цели. Сложность связана с необходимостью эффективно взаимодействовать с различными функциями базовой JVM.
Если вам не нужен какой-либо Java-interop, тогда 99% времени вам лучше всего придерживаться либо defrecord, либо простой карты Clojure.
- Используйте defrecord, если вы хотите использовать протоколы.
- В противном случае обычная карта Clojure, вероятно, самая простая и понятная
Если ваши потребности более сложны, то следующая блок-схема является отличным инструментом для объяснения того, почему вы выбрали один из этих вариантов над другими:
http://cemerick.com/2011/07/05/flowchart-for-choosing-the-right-clojure-type-definition-form/