Почему в 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

Блок-схема великолепна, но не охватывает всех возможностей или причин использования тех или иных вариантов или их комбинаций. Никакая простая диаграмма не могла.
— Марс
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.