Confused about resolving of classname

Go To StackoverFlow.com

5

two files

types.clj:

(ns test.types)

(defrecord Price [date price])
(defrecord ProductPrice [name prices])

core.clj (It's OK)

(ns test.core
  (:use [test.types])
  (:use [clojure.string :only (split)]))


(defn read-data [file]
  (let [name (subs (.getName file) 0 4)]
    (with-open [rdr (clojure.java.io/reader file)]
      (doall (map #(apply ->Price (split % #"\t")) (drop 2 (line-seq rdr)))))))

core.clj (java.lang.IllegalArgumentException: Unable to resolve classname: ProductPrice)

(ns test.core
  (:use [test.types])
  (:use [clojure.string :only (split)]))


(defn read-data [file]
  (let [name (subs (.getName file) 0 4)]
    (with-open [rdr (clojure.java.io/reader file)]
      (ProductPrice. name (doall (map #(apply ->Price (split % #"\t")) (drop 2 (line-seq rdr))))))))

core.clj (It's OK)

(ns test.core
  (:use [test.types])
  (:use [clojure.string :only (split)]))

(defrecord tProductPrice [name prices])
(defn read-data [file]
  (let [name (subs (.getName file) 0 4)]
    (with-open [rdr (clojure.java.io/reader file)]
      (tProductPrice. name (doall (map #(apply ->Price (split % #"\t")) (drop 2 (line-seq rdr)))))))

core.clj (java.lang.IllegalStateException: ->ProductPrice already refers to: #'test.types/->ProductPrice in namespace: test.core)

(ns test.core
  (:use [test.types])
  (:use [clojure.string :only (split)]))

(defrecord ProductPrice [name prices])
(defn read-data [file]
  (let [name (subs (.getName file) 0 4)]
    (with-open [rdr (clojure.java.io/reader file)]
      (ProductPrice. name (doall (map #(apply ->Price (split % #"\t")) (drop 2 (line-seq rdr)))))))

I totally confused about these exceptions. And I can't find any more usage about 'record' except some simplest examples from clojure.org and books.

Any help, Thank you very much!

2012-04-04 05:32
by Kane


9

defrecord creates a java class in the package named after the current namespace. (ProductPrice. ...) is a call to the constructor of that type; this is java interop - not a plain function call.

You cannot refer to a class defined outside of java.lang or the current namespace unless you explicitly import it or specify the full package name. This includes calling its constructor.

So, to fix the problem you need to import Price and ProductPrice.

 (ns test.core (:import [test.types Price]))
 (Price. ...)

or call the full class+package name:

 (test.types.Price. ...)
2012-04-04 10:12
by Joost Diepenmaat
Note that hyphen / underscore mangling in namespace names causes confusion here. If you defrecord something in clj-test namespace it will create a class in clj_test package and your :import will need to reflect thi - sw1nn 2012-04-04 10:51
@Joost Diepenmaat Thanks! Why ->Price can be used without import? And 'import' seems not work for me, still "java.lang.RuntimeException: java.lang.ClassNotFoundException: test.types.ProductPrice - Kane 2012-04-05 08:38
->Price is an additionally generated helper function which is a real clojure function, and so exported when you use the package. Also, you need to make sure the record types are compiled (use or require the namespace they're defined in) before you can import them. If you can't get that to work, please create a new question with example code - Joost Diepenmaat 2012-04-05 09:36
@JoostDiepenmaat, you should probably add what you wrote in your comment (Also, you need to make sure the record types are compiled (use or require the namespace they're defined in) before you can import them) to your answer; for a clojure noob like me, it was life saving - ThanksForAllTheFish 2014-12-22 16:14
Ads