Fork me on GitHub

Any stats on clojure usage? How many downloads per month in last 5 years? What is the rate of new people joining slack channel? Looks like universities overselling python to students


The annual State of Clojure survey has a lot of interesting stats

Jim Strieter15:09:26

I need to pickle a large map so that I can load it at a later time, kind of like setting an initial condition. Human readable is nice, but not strictly necessary. Seems to me that I could do this:

  (spit "my_file.clj" "(ns my-initial-condition)")
  (spit "my_file.clj" "(def initial-condition")
  (spit "my_file.clj" (str my-map) ;; <--- this is the important line
  (spit "my_file.clj" ")"))
Is there any reason why this would be a bad idea?


clojure.edn is the preferred way of storing map data for small files, and storing ns forms and defs in a file to mark state seems like it could go wrong in lots of strange ways. What are you trying to accomplish with this?

Jim Strieter15:09:29

I want to save program state periodically, and then give the user the option to load that state when starting


Who are the "users" in this scenario?


What program state needs to be saved? Loading ns forms and simple defs is usually fast and doesn't need to be persisted like this. Is there an expensive computation that you need to cache?

Jim Strieter15:09:35

expensive computation - yes

Jim Strieter15:09:28

I run digital filters on time series data. Startup will take > 15 min with no state loading. I want to reduce startup to a few seconds.


For expensive computation, you can do something like:

(defonce my-result
 (if (.exists ( "my-result.edn"))
    (clojure.edn/read (io/reader "my-result.edn"))
    (let [res (my-expensive-computation)]
      (spit "my-result.edn" (pr-str res))


That will make sure your expensive computation only happens once and take advantage of the persisted file if it's available.

Jim Strieter15:09:38

That's awesome


One thing to note with defonce -it really only does run once per session, which means that if the inputs to my-expensive-computation have changed, or my-expensive-computation has different implementation details (e.g. your filter parameters have changed), attempting to redefine the my-result var will not recompute your results. So you'll need to make those checks yourself.


You can always get around that by binding a new var, of course - just one thing to watch out for when using this approach.

Jim Strieter16:09:02

Yeah, I read up on defonce

Jim Strieter16:09:08

This is a slick solution


you can unbind vars whenever you want. in cider the command is ctrl-U

Jim Strieter21:09:52

@UFTRLDZEW do I need to import something to get io/reader? When I try just plain io, I get:

No such namespace: io
When I try, I get:
class cannot be cast to class


My bad, I wrote that answer without docs handy and forgot about the type conversion issue here:

Jeff Evans20:09:10

Is there a way to coax tools.cli into requiring the presence of some arg, when parsing, and not just ensuring that a value is provided if the flag is? Edit, just found:


Ugh! Looks like I forgot to update the docs/docstrings in several places when I added that. Sorry. It's listed here but that's a private function which doesn't appear in the API docs so that's not very helpful. tools.cli really does need some documentation love. I'll try to find some time to work on it "soon" (but, unfortunately, I've stopped using it in all my projects so it's become a lower priority).

Jeff Evans13:09:34

I can fork and update the at least. Should I add something to the existing example (with port number, etc.) or just do a new section?

Jeff Evans13:09:49

BTW I got my use case to work with :missing perfectly


Contrib libraries do not accept PRs so forking and updating isn't going to get accepted back. I need to write some proper documentation for that library -- it's long overdue!

Jeff Evans20:09:28

Ah, gotcha, thanks!


I've updated the README and docstrings for this. I'll be making a minor new release this weekend I expect.

👍 1