Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use \*print-dup\* to print records in clojure? A simple case

I'm trying to use *print-dup* to allow writing clojure data to a file and then read it back, however, I'm getting problems even with this simple case. Is there something I am doing wrong? What do I need to do to get this to work?

Clojure 1.3.0-alpha3-SNAPSHOT 
user=> (defrecord TreeNode [val left right]) ;;create the record 
user.TreeNode 
user=> (TreeNode. 5 nil nil) 
#:user.TreeNode{:val 5, :left nil, :right nil} ;; it works just fine 
user=> (binding [*print-dup* true] (prn (TreeNode. 5 nil nil))) ;; use *print-dup* to support reading in and preserving type 
#=(user.TreeNode/create {:val #=(java.lang.Long. "5"), :left nil, :right nil}) ;; this is the form we need to copy paste 
nil 
user=> #=(user.TreeNode/create {:val #=(java.lang.Long. "5"), :left nil, :right nil}) ;;trying to copy and paste 
IllegalArgumentException No matching method found: create 
clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:50) ;;we have an error 
user=>
like image 492
bmillare Avatar asked Dec 22 '10 19:12

bmillare


3 Answers

Records don't print in an eval-able form. We added our own defrecord2 that includes support for creating constructor functions and print/pprint support to print them using the constructor function (which can be eval'ed back into the original record). This is doc'ed more here and here and the code is here.

I asked Rich Hickey about this issue at the Clojure Conj conference in Oct. 2010 and he said constructor functions and reader support for records are planned for the future.

like image 125
Alex Miller Avatar answered Oct 16 '22 02:10

Alex Miller


As an update, as of alpha8, in the simple case, *print-dup* with records now works.

 user=> (defrecord TreeNode [val left right])
 user.TreeNode
 user=> (TreeNode. 5 nil nil)
 #user.TreeNode{:val 5, :left nil, :right nil}
 user=> (binding [*print-dup* true] (prn (TreeNode. 5 nil nil)))
 #user.TreeNode[5, nil, nil]
 nil
 user=> #user.TreeNode[5, nil, nil]
 #user.TreeNode{:val 5, :left nil, :right nil}
 user=> 
like image 3
bmillare Avatar answered Oct 16 '22 03:10

bmillare


Work around in 1.2:

(defn- extend-print-dup [record-class]
  (defmethod print-dup record-class [o w]
    (.write w "#=(")
    (.write w (.getName ^Class (class o)))
    (.write w ". ")
    (dorun (map (fn [a]  (print-dup a w) (.write w " ")) (vals o)))
    (.write w ")")))

(defrecord Hl7Field [protospec segname fname pos hl7type values])
(extend-print-dup Hl7Field)

=> (def a (Hl7Field. "p" "PV1" "toto" 0 "ST"  ["c" "d"]))
=> (binding [*print-dup* true] (prn a))
#=(higiebus.bus.protocol.hl7.Hl7Field. "p" "PV1" "toto" 0 "ST" ["c" "d"] )

=> #=(higiebus.bus.protocol.hl7.Hl7Field. "p" "PV1" "toto" 0 "ST" ["c" "d"] )
{:protospec "p", :segname "PV1", :fname "toto", :pos 0, :hl7type "ST", :values ["c" "d"]}

You could wrap the call to extend-print-dup in a custom defrecord macro.

like image 2
Luc Avatar answered Oct 16 '22 01:10

Luc