Welcome! Please see the About page for a little more info on how this works.

0 votes
in Compiler by

The following is valid Clojure (focus on extend-type (class (log-window-proxy nil)), as opposed to refering to a class literal):

(defn- log-window-proxy [state]
  (proxy [javax.swing.JTextArea clojure.lang.IDeref] []
    (deref [] state)
    (scrollRectToVisible [rect]
      (if @(:auto-scroll? state)
        (proxy-super scrollRectToVisible rect)))))

(defprotocol LogWindow
  (log   [this message])
  (clear [this]))

(extend-type (class (log-window-proxy nil))
  (log [this message]
    (println "message" message))
  (clear [this]

However, when one inspects the :tag metadata that this is given, it appears to have an somewhat odd form (since it remains a chain of calls, instead of a class literal):

(-> (extend-type (class (log-window-proxy nil))
      (log [this message]
        (println "message" message))
      (clear [this]
        nil)) quote macroexpand last :log second ffirst meta)
;; => {:tag (class (log-window-proxy nil))}

So, the :tag looks like a function call. Will the compiler end up invoking (class (log-window-proxy ... to obtain a class that it can actually use as a type hint?

Otherwise I'd be worried that this :tag metadata was invalid, which might cause reflection warnings and additionally confuse arbitrary third-party tooling.

1 Answer

+1 vote
selected by
Best answer

Why do you say this is valid Clojure?

The docstring implies to me that t is expected to be a class (not something that evaluates to a class). Whether it also works in the cited cases is incidental - I don't know that you should expect that to work. And the issue you raise is further evidence of that. extend-type is a helper wrapper around extend and you could use extend (a function) directly to get the evaluated class plus the specific type hint you seek if those differ in this special case.
Thanks for pointing out that `extend` can be a better alternative. It might be interesting to improve the Clojure compiler to support usages such as the two ones linked in my previous comment (plus my OP).

If that won't happen in a foreseeable future, I might refine the Eastwood linter to clearly inform of how to improve extend-type/extend-protocol usages.
I don't think it's a compiler issue but rather a question of what syntax `extend-type` is written to support.
Is there a definitive answer to that question at the moment?
My read on it is that extend-type currently expects a class, not something that evals to a class.