Использование подсказок типа в Clojure для возвращаемых значений Java

Я работаю над совместимостью Java/Clojure и наткнулся на предупреждение об отражении для следующего кода:

(defn load-image [resource-name]
  (javax.imageio.ImageIO/read 
    (.getResource 
      (class javax.imageio.ImageIO) 
      resource-name)))

=> Reflection warning, clojure/repl.clj:37 - reference to field read can't be resolved.

Я удивлен этим, потому что getResource всегда возвращает URL-адрес, и поэтому я ожидаю, что компилятор будет использовать соответствующий статический метод в javax.imageio.ImageIO/read.

Кстати, код отлично работает, поэтому он явно находит правильный метод во время выполнения.

Итак два вопроса:

  1. Почему это возвращает предупреждение об отражении?
  2. Какой тип подсказки мне нужен, чтобы исправить это?

person mikera    schedule 01.06.2010    source источник
comment
Я не получаю предупреждений об отражении с этим кодом. Не могли бы вы предоставить более подробную информацию о вашей настройке? (Версия Clojure — хотя я пробовал и 1.1, и передовую — и, по крайней мере, версию JVM.)   -  person Michał Marczyk    schedule 02.06.2010
comment
Я использую сборку Clojure 1.2 середины мая и JDK Java 1.6. Может стоит попробовать последнюю сборку 1.2?   -  person mikera    schedule 02.06.2010
comment
Sun JDK или OpenJDK? Что касается сборки, конечно, попробуйте, хотя у меня она работает как с моей собственной локальной сборкой, так и с выпуском 1.1.   -  person Michał Marczyk    schedule 02.06.2010
comment
Sun JDK - но, согласно приведенному ниже ответу Питера, проблема скорее в коде REPL, чем в приведенном выше коде. Так что надеюсь, что он уже исправлен для последней версии 1.2.   -  person mikera    schedule 02.06.2010
comment
Это действительно правильно? (класс javax.imageio.ImageIO) — это класс. Если вы хотите, чтобы класс ImageIO просто использовал его напрямую: (.getResource javax.imageio.ImageIO имя-ресурса).   -  person kotarak    schedule 02.06.2010
comment
Спасибо kotarak - твой вариант тоже работает и аккуратнее!   -  person mikera    schedule 02.06.2010
comment
mikera: Я протестировал это на нескольких сборках 1.2 и все равно не смог воспроизвести. Смотрите также мой комментарий к ответу Питера. Кстати, вы не пробовали новую сборку? Если да, я хотел бы знать номер коммита (или дату, или что-нибудь полезное, чтобы точно его идентифицировать) сборки, которую вы изначально использовали. Мне искренне любопытно об этом.   -  person Michał Marczyk    schedule 02.06.2010
comment
Привет, Михал. Я использую сборку 1.2.0-master-20100507.230258. Почти уверен, что предупреждение находится в коде repl.clj, а не в моем коде, но еще не понял, что я делаю, чтобы вызвать его..... p.s. Я также работаю в Eclipse, если вы думаете, что это может иметь значение?   -  person mikera    schedule 03.06.2010


Ответы (2)


AFAICS не имеет ничего общего с вашим кодом или компиляцией. Это часть функции source-fn REPL:

 ...
      (let [text (StringBuilder.)
            pbr (proxy [PushbackReader] [rdr]
                  (read [] (let [i (proxy-super read)]
                             (.append text (char i))
                             i)))]
 ...

и используется для отображения исходного кода в оболочке REPL, AFAICT.

person Peter Tillemans    schedule 02.06.2010
comment
Очень хорошее место! Угадайте, что это предупреждение для команды разработчиков Clojure, чтобы исправить это? - person mikera; 02.06.2010
comment
Предупреждения об отражении выдаются во время компиляции. К тому времени, когда что-то может быть введено в REPL, код REPL, конечно же, уже компилируется. На самом деле, материал в clojure.jar компилируется заранее, поэтому я не понимаю, как какие-либо связанные с ним предупреждения об отражении могут появиться в REPL. Более того, я все еще не могу воспроизвести эту проблему, и я попробовал текущий снимок Hudson, две локальные сборки 1.2 и банку выпуска 1.1. Просто пытаюсь внести в парад немного конструктивного дождя, чтобы помочь смыть любые оставшиеся препятствия на пути нашего понимания этого... - person Michał Marczyk; 02.06.2010
comment
Строка, на которую он жалуется в repl.clj: (proxy [PushbackReader] [rdr] (read [] (let [i (proxy-super read)] (.append text (char i)) i))) - интересно отметить, что предупреждение исчезает, если я помещаю (:use [clojure.repl]) в объявление ns перед строкой (set! warn-on-reflection true), так что, возможно, что происходит это изменяет время компиляции? - person mikera; 03.06.2010

Для других, которые находят этот пост (как и я), когда задаются вопросом, почему они получают предупреждения об отражении при использовании proxy-super...

Каждый прокси-метод имеет неявный this first arg, который, увы, не имеет подсказки типа (предположительно, потому что прокси реализует несколько возможных типов, а результирующий прокси-класс создается позже).

Таким образом, если вы когда-либо вызывали методы this из прокси-сервера (что в конечном итоге и делает proxy-super), вы увидите предупреждения об отражении.

Простое решение состоит в том, чтобы просто обернуть ваш код в let, который использует подсказки типов. Например.:

(let [^SomeClass this this]
  (proxy-super foo)
  (.bar this))
person Alex Taggart    schedule 24.06.2010