Учитывая, что вы используете тег Clojure, я предполагаю, что вас заинтересует специфичный для Clojure ответ:
какова цель пространства имен?
Пространства имен Clojure, пакеты Java, модули Haskell / Python / любые другие ... На очень высоком уровне это все разные имена для одного и того же базового механизма, основной целью которого является предотвращение столкновений имен в нетривиальных кодовых базах. Конечно, у каждого решения есть свои маленькие изюминки, которые имеют смысл в контексте данного языка и не имеют смысла вне его. Остальная часть этого ответа будет касаться завихрений и причуд, характерных для Clojure.
Группы пространств имен Clojure Vars , которые являются контейнерами, содержащими функции (чаще всего), макро-функции (функции, используемые компилятором для генерации макроразложений соответствующих форм, обычно определяемых с помощью defmacro
; на самом деле они просто обычные функции Clojure, хотя есть некоторая магия в том, как они регистрируются компилятором) и иногда различные «глобальные параметры» (скажем, clojure.core/*in*
для стандартного ввода), Atoms / Refs и т. д. Средство протокола, введенное в Clojure 1.2 обладает хорошим свойством, что протоколы поддерживаются Vars, как и отдельные функции протокола; это ключ к тому, как протоколы представляют решение проблемы выражения (что, вероятно, выходит за рамки этого ответа!).
Разумеется, пространства имен должны группировать переменные, которые так или иначе связаны между собой. В общем, создание пространства имен - это быстрая и дешевая операция, поэтому совершенно нормально (и действительно обычно) использовать одно пространство имен на ранних стадиях разработки, а затем, когда появляются независимые блоки функциональности, выделять их в свои собственные пространства имен, промыть и повторить ... Только вещи, которые являются частью общедоступного API, должны быть распределены между пространствами имен заранее (или, скорее: до стабильного выпуска), поскольку тот факт, что такая-то функция находится в пространстве имен, и так, конечно, является частью API.
и, что более важно, должны ли они использоваться как объекты в Java (вещи, которые имеют данные и функции и которые пытаются достичь инкапсуляции)? эта идея надуманна? :)
Обычно ответ - нет. Вы можете получить изображение не слишком далеко от истины, если подходите к ним как к классам со множеством статических методов, без методов экземпляра, без открытых конструкторов и часто без состояния (хотя иногда могут быть некоторые «члены данных класса» в форме Vars с атомами / ссылками); но, возможно, было бы более полезно не пытаться применять метафоры Java-ish к идиомам Clojure и подходить к пространству имен как к группе функций и т. д., а не к «классу, содержащему группу функций» или к чему-то подобному.
Существует важное исключение из этого общего правила: пространства имен, включающие :gen-class
в их ns
форме. Они предназначены именно для реализации Java-класса, который позже может быть создан, который может иметь методы экземпляра и состояние для каждого экземпляра и т. Д. Обратите внимание, что :gen-class
является функцией взаимодействия - чистый код Clojure, как правило, должен этого избегать.
или они должны использоваться как пакеты в java?
Они служат для тех же целей, для которых предназначены пакеты (как уже упоминалось выше); аналогия, хотя она и есть, не очень полезна, просто потому, что вещи, которые пакеты группируют (классы Java), совсем не похожи на вещи, которые пространства имен Clojure группируют (Clojure Vars), различные «уровни доступа» (private
/ package
/ public
в Java, {:private true}
или нет в Clojure) работают совсем иначе и т. Д.
При этом нужно помнить, что существует определенное соответствие между пространствами имен и пакетами / классами, находящимися в определенных пакетах.Пространство имен с именем foo.bar
при компиляции создает класс с именем bar
в пакете foo
;это означает, в частности, что имена пространств имен должны содержать хотя бы одну точку, так как так называемые односегментные имена, очевидно, приводят к тому, что классы помещаются в «пакет по умолчанию», что приводит к всевозможным странностям.(Например, я считаю невозможным, чтобы профилировщик VisualVM замечал какие-либо функции, определенные в односегментных пространствах имен.)
Кроме того, deftype
/ defrecord
созданные типы не находятся в пространствах имен ,Форма (defrecord Foo [...] ...)
в файле, где определено пространство имен foo.bar
, создает класс с именем Foo
в пакете foo.bar
.Чтобы использовать тип Foo
из другого пространства имен, нужно было бы :import
класс Foo
из пакета foo.bar
- :use
/ :require
не будет работать, так как они извлекают Vars из пространств имен,какие записи / типы не являются.
Таким образом, в данном конкретном случае существует определенное соответствие между пространствами имен и пакетами, о котором должны знать программисты Clojure, которые хотят воспользоваться некоторыми из новых возможностей языка.Некоторые считают, что это дает «вкус взаимодействия» к функциям, которые иначе не считаются принадлежащими к сфере взаимодействия (defrecord
/ deftype
/ defprotocol
- хороший механизм абстракции, даже если мы забываем об их роли в достижениискорость платформы на JVM), и вполне возможно, что в некоторых будущих версиях Clojure этот вариант может быть устранен, так что соответствие имени пространства имен / имени пакета для deftype
& Co. может рассматриваться как деталь реализации.
или они должны использоваться более широко как модульная система или как-то еще?
Они являются модульной системой, и это действительно так, как они должныиспользоваться.