I have written the following macro, that defines records with a custom string representation.
(defmacro defrecord*
[rname args]
`(defrecord ~rname [~@args]
Object
(toString [_]
~(let [kvs (->> args
(map (fn [arg] [(str arg ": ") arg]))
(interpose ", ")
(apply concat))]
`(str ~rname "(" ~@kvs ")")))))
However what toString returns is not quite what I am expecting.
(defrecord* Foo [bar baz])
(.toString (Foo. 3 4))
> "class user.Foo(bar: 3, baz: 4)"
I’d like my toString to return Foo(bar: 3, baz: 4) in this case. What change do I need to make to get a string representation in this format?
Also what changes, if any, should I make to the above code to make it more idiomatic?
Just replace
~rnamewith'~rname– you want the actual symbolFoo, not its value in the current scope, which is the classuser.Foo.You also have
(apply concat)and(interpose ", ")in the wrong order – you’ll be treating", "as a sequence, and adding\,and\spacecharacters instead of a single string. Once you swap that, it becomes clear that you wantmapcatinstead of(apply concat (map ...)). So I’d replace your whole let-block with something like:Or if you really want to grind out that performance, you can compute
~(str "(" rname)at compile-time instead of at runtime.Please note, though, that as of Clojure 1.3 records already print in a way very similar to this, so if you’re just doing this to make debugging easy, don’t bother. If you’re doing it because you’re using
.toString‘s output later on down the line…well, shame on whoever wrote that code, as.toStringis mostly for debugging stuff.