Share your thoughts in the 2021 Clojure Community Survey!

Welcome! Please see the About page for a little more info on how this works.

+1 vote
in ClojureScript by

I am trying to serialize my datascript database to JSON for storage on a filesystem.
Some of the data inside my database includes functions. For reasons that are not interesting, I need to store them in the database for now with other session info for the application. But I get an exception that transit "cannot write Function"

I looked at the code and it simply tries to handle data structures only - maps, vectors, etc. But there is no handler for functions. So I KNOW WHY I get the error, but the gist of my question is why it was not implemented to be able to serialize functions as well ?

Is it just too novel an thought ?

thanks

1 Answer

+2 votes
by

In Clojure, functions are opaque objects and you can't recover the source from the object.

by
Doesn't defn add the source as meta, which is how clojure.repl/source works?
by
No, defn stores the file and line number in var meta (not the function itself) and source uses that to find the source form, and reads it from the source file. This presumes that a) there is a variable and b) the source where it was defined is in an accessible file. In practice, neither may be true (and those are cases where source won't work).
by
Sounds like I hit the fundamental way that clojure(script) works and it is not a matter of just getting the time to implement it.  Thank you @alexmiller and @Didier A for the response. I now know better.
by
Ah I see. While this might get real hairy, in theory, you could write a modified defn and fn that stores the function source and environment only for those functions you want to serialize.

Something a little like what these attempt to do:

https://github.com/sorenmacbeth/serializable-fn
https://github.com/technomancy/serializable-fn

There's going to be caveats with that though. For example, they wouldn't transitively serialize the functions and macros that they themselves call. So when you deserialize them, you should be sure to do so under a namespace which has everything they need required.

Also, I'm not so sure you can do this in ClojureScript. You won't be able to eval when deserializing.

All in all, you probably want to approach the problem differently. But if this is more for fun, the above approach are pretty fun to mess with.
...