I may have missed the whole point about protocols but my question is, can protocols be used to dictate how to iterate a custom data structure or how println would print the object?
Assuming a map with two vectors,
{:a [] :b []}
When called first on it I would like to take from the :a vector but when conj on this structure i would like to conj to :b. Can I use protocols to achieve this type of behavior?
I was playing with custom collections and wanted to customise the output to the REPL so I ended up following Michal's advice on the last point. I have included the code snippet as to how to do this because I found sifting through the source took me a while as I didn't find this explained anywhere else.
This is handy, for example, in cases where the
seq
is always printing your custom vector with parentheses (as with Michal's example) and you want square brackets like regular Clojure vectors:It also means the way can now implement
seq
to actually return a sequence of your data type rather than just having to implement it for REPL output.Some things are still implemented as Java interfaces in Clojure; of those, I'd say some are likely to stay that way forever to ease cooperating with Clojure code from other JVM languages.
Fortunately, when defining a type using
deftype
, you can have the new type implement any Java interfaces you require (which Brian mentioned in a comment above), as well as any methods ofjava.lang.Object
. An example to match your description might look like this:A sample of what you can do with it at the REPL:
Note that the REPL prints it as a seq; I believe that's because of the inline implementation of
clojure.lang.ISeq
. You could skip it and replace theseq
method with one returning(seq a)
for a printed representation using the customtoString
.str
always usestoString
, though.If you need custom behaviour of
pr
family functions (includingprintln
etc.), you'll have to look into implementing a customprint-method
for your type.print-method
is a multimethod defined inclojure.core
; have a look at core_print.clj in Clojure's sources for example implementations.