Использование протокола с примитивными аргументами

Я пытаюсь определить протокол в Clojure 1.4 с примитивными аргументами (чтобы я мог избежать ненужного примитивного бокса в чувствительном к производительности коде):

(defprotocol A
  (foo [a ^long x]))

(extend-type java.lang.String A 
  (foo [s ^long x] (.charAt s x)))

Похоже, что это работает нормально, но не удается, за исключением, когда я пытаюсь его использовать:

(foo "abracadarbra" 3)
=> ClassCastException XXXX cannot be cast to clojure.lang.IFn$OLO

Что я делаю неправильно?

2 ответа

Решение

После дальнейших исследований выясняется, что протоколы еще не поддерживают подсказки примитивного типа (начиная с Clojure 1.4). Смотрите, например, https://groups.google.com/d/topic/clojure-dev/HxBqIewc494/discussion

Альтернативы кажутся:

  • Написать регулярные функции с примитивными подсказками. Вы теряете полиморфизм.
  • Используйте интерфейс Java (вы можете использовать reify для создания экземпляров в Clojure)

Взять подсказку типа из defprotocol и оставить его в extend-type

(defprotocol A
(foo [a x]))

(extend-type java.lang.String A 
  (foo [s ^Long x] (.charAt s x)))
nil
core> (foo "abracadarbra" 3)
\a

или вы можете изменить подсказку типа следующим образом:

(defprotocol A
(foo [a ^Long/TYPE x]))

(extend-type java.lang.String A 
  (foo [s ^long x] (.charAt s x)))
nil
core> (foo "abracadarbra" 3)
\a

это все еще не дает никаких отражений предупреждения без намека на defprotocol

РЕДАКТИРОВАТЬ:

(extend-type java.lang.String A 
  (foo [s ^Long x] (type x)))
nil
core> (foo "abracadarbra" 3)
java.lang.Long
Другие вопросы по тегам