Перезагрузка мультиметодов через Slime - PullRequest
3 голосов
/ 21 февраля 2012

У меня проблемы с перезагрузкой мультиметодов при разработке в Emacs с использованием реплик Slime.

Переопределение форм defmethod работает нормально, но если я изменю функцию отправки, я не смогу перезагрузить форму defmulti. Я думаю, что я специально добавил или удалил параметры функции отправки.

В качестве обходного пути я смог ns-unmap мультиметодный var, перезагрузить форму defmulti, а затем перезагрузить все формы defmethod.

Предположительно, это "ограничение" способа, которым Clojure реализует мультиметоды, т. Е. Мы жертвуем некоторым динамизмом для скорости выполнения, но есть ли идиомы или методы разработки, которые помогут обойти это?

1 Ответ

8 голосов
/ 21 февраля 2012

Короткий ответ: ваш способ борьбы с этим абсолютно верен.Если вы обнаружите, что обновляете мультиметод с целью частого изменения функции диспетчеризации, (1) я думаю, что это необычно :-), (2) вы можете написать набор функций / макросов, чтобы помочь с перезагрузкой.Ниже я делаю набросок двух непроверенных (!) Макросов, чтобы помочь с (2).

Почему?

Сначала, однако, краткое обсуждение вопроса «почему».Функция диспетчеризации для поиска мультиметода, реализованная в настоящее время, не требует синхронизации - диспетчеризация fn хранится в поле final объекта MultiFn.Это, конечно, означает, что вы не можете просто изменить функцию диспетчеризации для данного мультиметода - вы должны воссоздать сам мультиметод.Это, как вы указываете, требует перерегистрации всех ранее определенных методов, что создает трудности.

Текущее поведение позволяет перезагружать пространства имен с формами defmethod в них, не теряя при этом все свои методы за счет затрат.сделать немного более громоздким замену фактического мультиметода, когда это действительно то, что вы хотите сделать.

Если вы действительно хотите, диспетчер fn можно изменить с помощью отражения, но это имеет проблематичную семантику, особенно вмногопоточные сценарии (см. Спецификация языка Java 17.5.3 для получения информации об отражающих обновлениях полей final после построения).

Хаки (неотражающие)

Один из подходов к (2) состоит в том, чтобы автоматизировать повторное добавление методов после переопределения с помощью макроса в соответствии с (непроверенным)

(defmacro redefmulti [multifn & defmulti-tail]
  `(let [mt# (methods ~multifn)]
     (ns-unmap (.ns (var ~multifn)) '~multifn)
     (defmulti ~multifn ~@defmulti-tail)
     (doseq [[dispval# meth#] mt#]
       (.addMethod ~multifn dispval# meth#))))

Альтернативный дизайн будет использовать макрос, скажем, скажем, with-method-reregistrationвзяв последовательность из нескольких имен и тела и пообещав перерегистрировать методы после выполнения bоды;вот эскиз (опять же, не проверенный):

(defmacro with-method-reregistration [multifns & body]
  `(let [mts# (doall (zipmap ~(map (partial list 'var) multifns)
                              (map methods ~multifns))))]
     ~@body
     (doseq [[v# mt#] mts#
             [dispval# meth#] mt#]
       (.addMethod @v# dispval# meth#))))

Вы бы использовали его, чтобы сказать (with-method-reregistration [my-multi-1 my-multi-2] (require :reload 'ns1 ns2)).Не уверен, что это стоит потери ясности.

...