Hey Marshall,
Yeah CLJ-1074 is something I've already voted for and wished for more
than once. I would encourage others to go vote it up as well since
that's the official indicator of interest in a patch besides talking
about it here.
So in Haskell, read and print are defined to be an isomorphism, which is
awesome because it means you can read anything you can print thus giving
you naive serialization for free. For most actual data types (besides
primitive arrays and soforth) Clojure's read-string and pr are an
isomorphism and I agree that they should be such over data.
Last night, to hack around unreadable #< ... > forms occurring in
existing EDN files I cooked up this hack:
https://github.com/clojure-grimoire/lib-grimoire/blob/develop/src/grimoire/api.clj#L184-L191
which isn't even correct due to the possibility of nested #<> forms ala
#< .. #<>> but was good enough to get my prototype of the next Grimoire
release running.
The "real" fix,
https://github.com/clojure-grimoire/lein-grim/blob/develop/src/grimoire/doc.clj#L110
being "just don't pr unreadable things!" I find unsatisfactory because
the pr documentation
http://conj.io/1.6.0/clojure.core/pr says that the
output of pr is readable when clearly it may not be. However this leaves
us where you leave off trying to print things with no really meaningful
read representation.
pr of a var could be #var clojure.core/concat or #'clojure.core/concat
which could be resolved when read to the var as interred in the reading
Clojure instance's memory. Note that while this _may_ be an isomorphism,
it need not be because a given var may have an altered binding or even a
different root definition in another Clojure instance. This is why the
pr of a var explicitly wraps the pr of the var's value. Maybe it does
make sense to just make the existing pr of a var readable, but that
still doesn't solve the subproblem that the value form must be readable.
What is the pr of a function? We can't reasonably pr an equivalent
lambda expression that could be read, nor can we simply pr the address
of the instance as we do now. This is specifically the case that I was
choking on last night with lib-grimoire: some functions in core have
:inline metadata which has a function as a value.
What is the pr of Object[]? It could contain arbitrary unreadable
classes... itself even :|
I guess the "obvious" solution to me would be to have an "unreadable"
symbol which is defined to be the pr value of any value which cannot be
meaningfully serialized as outlined above. This is obviously
unsatisfactory, since it clearly admits that (comp read pr) is not an
identity operation. The good news is that we don't need a new
"unreadable" value (although we could have one). As "unreadable" would
be meaningless as a value, we already have a value that's meaningless:
nil. We can't define pr of unreadable things to be an empty string, then
we have issues with printing vars and maps and soforth we can no longer
naively print for fear of generating unreadable syntax so pring nil may
just be the least evil thing to do.
The only other thing we can really do is stay where we are at "don't
print unreadable things!" which requires that users be aware of what is
and isn't a readable value.
Just some thoughts.
Reid