Question

I've got a problem understanding how protocols works in Clojure. More specifically I think that my problem is related as to when classes are generated (?).

I managed to reproduce my issue with the simple following case. I have three files:

core.clj

(ns so.core
  (:require [so.soproto :refer :all])
  (:import  [so.soimpl AImpl])
)

(defn -main [] (println "Hello, World!"))

soproto.clj

(ns so.soproto)

(defprotocol A
  (do-smth [this]))

soimpl.clj

(ns so.soimpl
    (:require [so.soproto :refer :all]))

(deftype AImpl
    []
  A
  (do-smth [this] (println "whatever")))

Now if I try to "lein run", I get this:

$ lein run
Exception in thread "main" java.lang.ClassNotFoundException: so.soimpl.AImpl

I can reproduce the issue from Emacs using the following procedure:

  • open core.clj
  • call Emacs' cider-jack-in
  • switch cider's REPL to the namespace so.core
  • cider-eval-buffer

Surely enough I get the same exception:

java.lang.ClassNotFoundException: so.soimpl.AImpl

Now I can "fix" the problem from within Emacs by doing this:

  • switch to buffer soimpl.clj
  • cider-eval-buffer
  • switch back to core.clj
  • cider-eval-buffer -> now things do work fine

So how can I get "lein run" to work? And how can I, from cider / Emacs, do a cider-eval-buffer on only core.clj without needing to open / eval the file containing the protocol implementation?

Was it helpful?

Solution

If you are importing a class, it needs to be compiled first. Add :aot [so.soimpl] to the defproject options in lein's project.clj.

Note, however, you do not really need to AOT compile / import AImpl to use it. Just refer in its constructor instead.

(:import [so.soimpl AImpl])

(require [so.soimpl :refer (->AImpl)])

See this recent answer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top