views:

85

answers:

1

I have a project set up with leiningen called techne. I created a module called scrub with a type in it called Scrub and a function called foo.

techne/scrub.clj:

(ns techne.scrub)
  (deftype Scrub [state]
    Object
     (toString [this]
     (str "SCRUB: " state)))

(defn foo
  [item]
  (Scrub. "foo")
  "bar")

techne/scrub_test.clj:

(ns techne.scrub-test                                                                                                                                             
  (:use [techne.scrub] :reload-all)                                                                                                                               
  (:use [clojure.test]))                                                                                                                                          


(deftest test-foo                                                                                                                                                 
  (is (= "bar" (foo "foo"))))                                                                                                                                                           

(deftest test-scrub                                                                                                                                               
  (is (= (Scrub. :a) (Scrub. :a)))) 

When I run the test, I get the error:

Exception in thread "main" java.lang.IllegalArgumentException: Unable to resolve    classname: Scrub (scrub_test.clj:11)
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:5376)
    at clojure.lang.Compiler.analyze(Compiler.java:5190)
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:5357)

If I remove test-scrub everything works fine. Why does :use techne.scrub 'import' the function definitions but not the type definitions? How do I reference the type definitions?

+3  A: 

Because deftype generates a class, you will probably need to import that Java class in techne.scrub-test with (:import [techne.scrub Scrub]) in your ns definition.

I actually wrote up this same thing with respect to defrecord here:

Another thing you could do would be to define a constructor function in scrub:

(defn new-scrub [state] 
  (Scrub. state))

and then you would not need to import Scrub in test-scrub.

Alex Miller
I always use constructor functions for this reason, and for validation.
Stuart Sierra
Yep, we have found it helpful to extend defrecord to automatically add constructor functions with field validation, pprint support to an eval-able form, etc.
Alex Miller