Can someone teach me how I can override the "toString" method for a struct ?
Here's a code snippet that shows what I'm trying to do:
user> (defstruct bookinfo :book :filename)
user> (struct bookinfo "hello" "world") => {:book "hello", :filename "world"}
I would like to override the "toString" method on a struct so that the
following behavior is true:
user> (struct bookinfo "hello" "world") => "hello"
In Common Lisp, I would simply define a method on (print-object). What
would be the equivalent thing in Clojure?
I already tried the following but it doesn't seem to work
(sorry...i've been programming Clojure for only two days):
user> (defmulti .toString class)
user> (defmethod .toString clojure.lang.PersistentStructMap [s]
(:book s))
Thanks for your help.
Regards,
Jung Ko
> As Mike said, it's done by adding a method to print-method, but you
> will need metadata... "structs" in clojure are nothing but an
> optimisation of maps... That is, in all situations structmaps are (at
> least, should be) interchangeable with a regular persistent map. They
> do not create their own type or anything, so you can't override their
> toString method directly.
>
> However, since print-method uses :type metadata, you can do the
> following:
>
> ;; using ::foo to get namespace-qualified keywords is good for type
> tags, because it avoids collisions
> ;; typed-book could be a struct-map, or in fact any implementation of
> Map that also supports metadata
> (def typed-book (with-meta {:book "somebook"} {:type ::my-book})) ;
> the latter map is the metadata
> (defmethod print-method ::my-book [thebook writer]
> (print-method (:book thebook) writer)) ; falls back to the string
> writer
>
> (print typed-book) ; prints 'somebook'
Thank you Mike and Jarkko for the detailed answer. It works as you described. :)
Sincerely,
Jung Ko