Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overloading keywords in Clojure

Tags:

clojure

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?

Update:

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

Update 2

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
like image 594
yazz.com Avatar asked Apr 07 '11 15:04

yazz.com


1 Answers

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"
like image 109
mikera Avatar answered Sep 18 '22 11:09

mikera