Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Environment variables used in `def` statements in Clojure

I have this piece of code:

(def heavy_computation (f1 (env :var1)))

where (env :var1) is fetching environment variable VAR1 (with the help of environ) that points to a directory location and f1 is a wrapper around Java function. This is used later in functions and it is heavy computation that I would like to compute just once.

I want to be able to customize VAR1 and print an error message if it is missing in production.

If I compile this code lein uberjar without environment variables, it throws an error about NullPointerException at this line.

I can compile it with environmental variables and later if I set them appropriately, it will work. In order to print my error message in case it is missing, I have to put the code that checks it right before the def statement, otherwise it throws null pointer exception.

Can I do it in a cleaner way? I don't want to set environment variables in order to compile it and I want to put the code that performs checks in the -main function right before it starts the server.

like image 821
Dmitry Matveyev Avatar asked Dec 24 '22 05:12

Dmitry Matveyev


2 Answers

One option is to wrap the evaluation in a delay:

(def heavy-computation (delay (f1 (env :var1))))

Then wherever you need the result, you can deref/@ the delay:

(when (= :ok @heavy-computation)
  (println "heavy!"))

The delay's body will only be evaluated once, and not until you dereference it.

like image 75
Taylor Wood Avatar answered Jan 06 '23 13:01

Taylor Wood


Wrap the environment value in an if-let and handle the else branch with printing a warning. During compilation you will see the warning, but that would be OK with me personally. You can also use a memoized function instead of a delay to defer the computation.

like image 38
Michiel Borkent Avatar answered Jan 06 '23 13:01

Michiel Borkent