Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

var or ref/atom/agent for constant values?

I would like to humbly ask...

What, "var or ref/atom/agent for constant values?", do I ask? Of course, I do use vars for constant values.

But I always wondered which one I should use when the values act like constants but they should be assigned in run-time, rather than in compile-time(when the codes are read).

For example, think some java properties written in user's config file. They should be assigned in run-time because the data is not in the codes. But they also should be defined before the data is read, since the other codes refer them.

In this case,

when do I use 'var's?:

  • I define 'var's, or just declare 'var's (when that's okay).
  • And then I redefine those 'var's again by functions that read option files.
  • But it feels terrible to overwrite 'var's, or it feels strange to define 'var's inside functions.

when do I use ref/atom/agent?:

  • I assign ref/atom/agents to 'var's.
  • An then I update those ref/atom/agents by functions that read option files.
  • But since the values are used throughout the program so I worry their costs.
  • ... and using too many @ macros are somewhat annoying.

I don't know what I should use.

What do you use in those cases?

'var's? 'ref/atom/agent's? or even 'delay's?

Thanks in advance.

like image 447
Bak Yeon O Avatar asked Nov 02 '22 10:11

Bak Yeon O


1 Answers

If all, or a group, of "constants", you are taking about, can be learned at a single point in time, let's call them "properties" instead.

And let's make a config that would "suck them in":

(defn resource [path]
  (when path
    (-> (Thread/currentThread) .getContextClassLoader (.getResource path))))

(def props
  (edn/read-string 
    (slurp (io/file (resource (System/getProperty "your.conf"))))))

(defn conf [& path]                  ;; e.g. (conf :db :uri)
  (get-in props (vec path)))

Your properties (e.g. "constants") file "your.conf" would be in the lines of:

{:db
    {:uri "datomic:mem://dbname"
     :other-property 42}

 :rabbit
        {:host "192.168.1.17"
         :port 5672
         :exchange "xyz-exchange"
         :queue "zq"
         :exchange.type "direct"
         :vhost "/some-broker"
         :username "user"
         :password "strong"}}

Then later in your program/other namespaces you can access all this properties as:

(conf :db :uri)               ;; will "constant"ly return "datomic:mem://dbname"
(conf :rabbit :host)          ;; will "constant"ly return "192.168.1.17"
(conf :db :other-property)    ;; will "constant"ly return 42

In "real life", the "props" var above would potentially check a "-D" path, have defaults, and handle exceptions, but it is a bit simplified to illustrate the point.

like image 56
tolitius Avatar answered Dec 07 '22 12:12

tolitius