defmulti будет расширен с LET-блоком, который использует def
для определения символа. На самом деле выражение, возвращаемое defmulti
, не будет оцениваться, но оно будет сгенерировано как форма, используя let. Таким образом, объект становится глобальным. Это приводит к тому, что ваше тестовое условие (если оно не удастся) преуспеть после того, как было определено var, до создания мультифайла и повреждение корневого каталога var. Ваш defmulti-блок никогда не исполнялся (также когда-не выражение, возвращенное nil), но расширено.
Дальнейшее объяснение:
Здесь вы можете увидеть, как это происходит:
(macroexpand '(defmulti buxx class))
Теперь вы можете увидеть форму, что Макровызы будут генерировать:
(clojure.pprint/write (macroexpand '(defmulti buxx class))
:with-dispatch clojure.pprint/code-dispatch)
=>
(let*
[v__4080__auto__ (def buxx)]
(clojure.core/when-not
(clojure.core/and
(.hasRoot v__4080__auto__)
(clojure.core/instance? clojure.lang.MultiFn @v__4080__auto__))
...
Это приводит к (def buux)
расширяется. Если вы оцениваете (def buux)
в своем repl, вы можете сделать те же тесты.
С ДЕФа строку документации:
Защиту дает сам вар (а не его значение).
Это означает, что при его расширении он заменяется (возможно, несвязанным) var.
Поэтому при расширении def всегда создает var, но необязательная форма, которая возвращает новое значение (для var), будет оцениваться только при вычислении расширенного def. Макросы и специальные формы будут расширены до их фактической оценки. E. g. испытания с использованием
(defmacro i-have-side-effects
[]
(println "I was invoked!")
42)
(when-not true
(println (i-have-side-effects)))
=>
#'user/i-have-side-effects
I was invoked!
nil
Так что, вероятно, вы не должны определять мульти-метод условно в любом случае.
@Rainer Joswing, Clojure - это Lisp. Зачем удалять тег? – missingfaktor
Clojure - это язык, основанный на Lisp. вопрос настолько Clojure, что маловероятно, что любой, скажем, пользователь Emacs Lisp мог бы внести свой вклад в это. Я также не буду отмечать специальные вопросы C++ с помощью тега Algol или C. Операторы, о которых вы упомянули, defmulti и when-not также не являются особыми для Clojure, а также последствия их использования. –