The root cause of the "Can't embed object in code, maybe print-dup not defined" with an object that has "reify" and a bunch of hex digits in its printed representation, is the following combination of factors:
(1) Clojure primitive vectors are defined with deftype.
(2) For all types defined via deftype, there is an emitValue Java method inside of Clojure's Compiler.java source file that has many cases for deciding how to embed a literal value in JVM byte code. You can search that file for the first occurrence of "IType", which is a Java interface that Clojure deftype-created types all implement, in order to later recognize that they were objects of a class created via deftype. When such an object is a literal inside of Clojure code, emitValue attempts to create JVM byte code that can construct the original value when that JVM byte code is later executed, and for deftype-created objects, it always tries to iterate through all fields of the object, and emit code for the field and its value.
(3) Clojure primitive vectors have a field "am", short for "array manager", that is an object created by calling Clojure's "reify" function. This object is used to implement several Java methods on 'leaves' of the tree used to represent Clojure primitive vectors, one such object for each different primitive type, since the JVM byte code for dealing with arrays of each primitive type is different, and Rich was probably going for run-time efficiency here by not detecting the primitive type at run time on every operation, but instead having an object that already had baked into it code for dealing with that vector's primitive type.
(4) emitValue, when called with an object that is the return of a "reify" call, tries to call `RT.printString` on it, which would work if a `print-dup` method were defined to handle such objects, but in general objects returned by "reify" can have arbitrary references to other JVM objects with internal state, or can have internal state themselves, so there is no good general way to create a `print-dup` definition that handles all possible objects created by calling "reify".
What could be done about this?
There are probably many alternatives I haven't thought of, but here are a few potential approaches, most of which would require changing Clojure's implementation in some way.
Change Clojure's primitive vector implementation so that all of its field values were immutable values with printable representations, i.e. no objects returned from 'reify', nor any function references. Since primitive vectors are trees with O(log_32 n) depth, the representation created via emitValue would reflect that tree structure, but it seems like it could be made to work correctly. This would likely lead to some lower run-time performance of operations on primitive vectors, since there would need to be a "case" or other conditional code to handle the different primitive types in leaf nodes.
Create a new implementation of Clojure primitive vectors that uses deftype, but has the changes suggested in #1a above. No changes to Clojure's implementation would be required, since it would be a 3rd party implementation that can make its own implementation choices.
Change the emitValue method in Compiler.java so that for deftype-created objects, it somehow checked whether there was a print-dup method for that object's class first, and used it if it was available, falling back to the current approach if there was not. That would be somewhat tricky in this case, because Clojure primitive vectors implement the clojure.lang.IPersistentCollection interface, which already has a print-dup method that will not work for primitive vectors. One possibility is not to simply call print-dup and see what happens, but to check whether the print-dup multimethod has an implementation for _exactly_ the class of the object one is trying to do emitValue on, e.g. clojure.core.Vec for primitive vectors. Such an exact class check for multimethod implementations seems against the philosophy of multimethods in Clojure, and seems a bit hackish.
Another cleaner variation on this idea would be to define a new "emittable" interface in Clojure's implementation, and if a deftype-created class implemented it, then emitValue would use the 'emit' method of that interface on objects that implemented it.
Create a separate Clojure primitive vector implementation that does not use deftype, nor defrecord, and falls into the last "else" case of the long if-then-else daisy chain of Clojure's emitValue. This seems difficult, or maybe impossible, to me, without changing the emitValue method, because it currently has a case for clojure.lang.IPersistentVector before the last "else", and it would be very strange to try creating a Clojure primitive vector implementation that did not implement that interface.
Of the ones I have thought about, approach #1b, or the last variant of approach #2, seem possibly workable. #1b requires no changes to Clojure's implementation. #2 definitely does. Approach #3 probably isn't really a viable alternative, for reasons stated above.
More details can be found in this repo's README: https://github.com/jafingerhut/vec-data-reader