views:

72

answers:

2
(deftype Bag [state]
   Object
     (toString [bag]
       (str "Bag???" state)))

I want the toString to look something like

clojure.core=> (def b (Bag. {:apples 1 :bannanas 4}))
#'clojure.core/b
clojure.core=> (str b)
"BAG: {:apples 1 :bannanas 4}"

What is a nice clojurey way of representing that information? Is

"Bag/{:k :v}" 

better? How does the community do you call your toStrings?

+4  A: 

Depending on exactly what you're trying to do, the simplest way is to use defrecord:

user=> (defrecord Bag [state])
user.Bag
user=> (def b (Bag. :foo))
#'user/b
user=> b
#:user.Bag{:state :foo}

Though what you see above is from pr, not str:

user=> (str b)
"user.Bag@53e935f4"
user=> (prn b)
#:user.Bag{:state :foo}
nil

So we just make a change:

user=> (defrecord Bag [state]
         Object
         (toString [bag] (pr-str bag)))
user.Bag
user=> (def b (Bag. :foo))
#'user/b
user=> (str b)
"#:user.Bag{:state :foo}"
user=> (.toString b)
"#:user.Bag{:state :foo}"

Now, if the above is not suitable, then next option would be to add a new method to the print-method multi-method. Google around for details on that.

Aside: Using defrecord should generally be preferred over deftype unless you're doing something very low-level.

Alex Taggart
Define low level. I'm trying to create new collection types (bags and multimaps). When do you use defrecord or deftype and why?
Nick Orton
Using this method with deftype yields a java.lang.StackOverflowError
Nick Orton
Yes, if you're creating new collection type, deftype is probably correct, whereas defrecord is more appropriate when needing something like a struct of some domain data.
Alex Taggart
+2  A: 

The following is for deftype.

user=> (deftype Bag [state] 
         Object 
         (toString [_] 
           (str "BAG: " (pr-str state))))
user.Bag
user=> (def b (Bag. {:apples 1 :bannanas 4}))
#'user/b
user=> (str b)
"BAG: {:bannanas 4, :apples 1}"
Alex Taggart