I have a map like this:
(def a {:a 1, :b 2})
: I wish to overload the map so that some keywords execute functions so that :
(c: a)
Can execute a function. Is this possible?
I do realise that I could do something like:
(def a {:a (fn[] 1) :b (fn[] 2) :c (fn[] x)})
:and:
((c: a))
: but then I have to convert every existing map entry I have to a function.
I want the function "reevaluated" every time. For example when I do :
(def ab{:a 1 :b 2 :c ( #(.nextInt (java.util.Random.) 1000))})
(str (:c ab) " " (:c ab) " " (:c ab))
I get:
61 61 61
Instead of three different numbers
I thought about the answer I was given and realised that he is right, I should use immutable structures only. The final solution I came up with was to have an "enrich" function which creates the dynamic properties on demand.
(def a {:a 1, :b 2})
: I wish to overload the map so that some keywords execute functions so that :
(str (:c (enrich ab)) " " (:c (enrich ab)) " " (:c (enrich ab)))
will produce different numbers each time like so:
58 639 710
I believe it is possible to override the behaviour of associative lookups if you make your data structure a record rather than a regular map.
You basically need to override clojure.lang.ILookup : see this question for more details
Here's a quick example:
(deftype TestLookup []
clojure.lang.ILookup
(valAt [this k not-found]
(str "Generated value for key - " k))
(valAt [this k]
(.valAt this k nil)))
(def lookupable-object (TestLookup.))
(:somekey lookupable-object)
=> "Generated value for key - :somekey"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With