Search code examples
clojure

Does the order of function calls inside a Clojure map guarantee runtime order processing?


I'm working on the following function:

(defn process-request [request]
  (if (not (db/empty?))
    {:person (db/get-person!) :violations (:violations (process-violations request))}
    {:person {} :violations ["no-person"]}))

I need the process-violations function to only be called if the db is not empty. That's why it's in the if block.

However, I also need it to be called before the db/get-person! function. Otherwise, the value will be outdated.

So I wonder:

  • How would I do that?
  • And anyway, is the order of values in a map enough to guarantee that a function will always be called before another?

Solution

  • No, maps are not ordered. For small literal maps it will probably work, but you should not rely on it, and for larger maps it indeed does fail:

    user=> {0 (println 0) 1 (println 1) 2 (println 2) 3 (println 3) 4 (println 4) 5 (println 5) 6 (println 6) 7 (println 7) 8 (println 8) 9 (println 9)}
    0
    7
    1
    4
    6
    3
    2
    9
    5
    8
    {0 nil, 7 nil, 1 nil, 4 nil, 6 nil, 3 nil, 2 nil, 9 nil, 5 nil, 8 nil}
    

    But it is always easy to force ordering by using let bindings, which are evalauted, in order, before the let body.

    (let [person (db/get-person!)]
      {:person person :violations ...})