Почему в Clojure есть 5 способов определить класс вместо одного?

84

Clojure имеет gen-class, reify, proxy, а также deftype и defrecord для определения новых типов данных, подобных классам. Для языка, который ценит синтаксическую простоту и не терпит ненужной сложности, это кажется отклонением. Может кто-нибудь объяснить, почему это так? Может ли быть достаточно дефекласса в стиле Common Lisp?

Салил
источник

Ответы:

91

Это сочетание трех разных факторов:

  1. Система конкретных типов jvm
  2. Необходимость в несколько иной семантике для разных случаев использования при определении типов
  3. Дело в том, что некоторые из них были разработаны раньше, а некоторые позже, по мере развития языка.

Итак, сначала давайте рассмотрим, что они делают. deftype и gen-class похожи в том, что оба они определяют именованный класс для предварительной компиляции. Первым был Gen-class, а затем deftype в clojure 1.2. Deftype является предпочтительным и имеет лучшие характеристики производительности, но является более ограничительным. Класс deftype может соответствовать интерфейсу, но не может наследовать от другого класса.

Reify и прокси используются для динамического создания экземпляра анонимного класса во время выполнения. Первым был прокси, а в clojure 1.2 появились reify с deftype и defrecord. Reify предпочтительнее, так же как и deftype, где семантика не слишком строгая.

Остается вопрос, почему и deftype, и defrecord, поскольку они появились одновременно и имеют схожую роль. Для большинства целей мы захотим использовать defrecord: у него есть все различные возможности закрытия, которые мы знаем и любим, sequability и так далее. Deftype предназначен для использования в качестве строительного блока нижнего уровня для реализации других структур данных. Он не включает обычные интерфейсы clojure, но имеет возможность изменять поля (хотя это не по умолчанию).

Для дальнейшего чтения ознакомьтесь с:

Страница типов данных clojure.org

Тема группы google, где были представлены deftype и reify

Роб Лахлан
источник
1
Тема группы Google была очень ценной. Я понимаю, что для прокси-сервера java-interop, gen-class в основном заменяются reify и deftype. Я рад, что теперь у нас меньше «рекомендуемых» способов определения типов.
Салил
2
@Trylks: возможность обрабатывать объект как последовательность пар ключ-значение. Практически все, что является родным для clojure, можно рассматривать как последовательность, что очень эффективно.
Роб Лахлан
proxyиногда предпочтительнее, потому что он позволяет изменять методы во время выполнения. (например, The Joy of Clojure , 2-е изд. предполагает, что это может быть удобно для изменения обратных вызовов в веб-обработчике.)
Марс,
52

Короткий ответ: все они имеют разные и полезные цели. Сложность связана с необходимостью эффективного взаимодействия с различными функциями базовой JVM.

Если вам не нужно взаимодействие с Java, то в 99% случаев лучше придерживаться либо defrecord, либо простой карты Clojure.

  • Используйте defrecord, если хотите использовать протоколы
  • В противном случае обычная карта Clojure, вероятно, будет самой простой и понятной.

Если ваши потребности более сложные, то следующая блок-схема - отличный инструмент для объяснения, почему вы бы предпочли один из этих вариантов другим:

http://cemerick.com/2011/07/05/flowchart-for-choosing-the-right-clojure-type-definition-form/

Блок-схема для выбора правильной формы определения типа закрытия

Микера
источник
1
Большое спасибо за ссылку на блок-схему. Помогает то, что блог ведется соавтором книги Орейли - Programming Clojure. Я считаю, что это довольно сложный процесс принятия решения. Являются ли различия между интерфейсом и конкретным классом, или необходимость определять статические методы, или именованный тип, или анонимный тип, настолько велики, что им нужна другая языковая конструкция?
Салил
4
различия не велики, но они отличаются философски с точки зрения того, чего вы пытаетесь достичь. Я думаю, что множественные подходы в Clojure отражают эти основные различия, и это хорошая причина, почему им следует давать разные имена.
mikera
Блок-схема великолепна, но не охватывает всех возможностей или причин использования тех или иных вариантов или их комбинаций. Никакая простая диаграмма не могла.
Марс