Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simplest possible Clojure object that can accept a primitive and metadata?

I want to add metadata to a byte array in Clojure. Since this is not allowed, one option I want to try is the simplest object wrapper that could work.

Here is the source code for with-meta.

That made me start looking at Clojure.lang.IObj. I haven't found what I want yet.

like image 514
David J. Avatar asked Dec 21 '13 22:12

David J.


1 Answers

Here's how you can create a deftype that supports metadata.

(import '(java.io Writer))

(deftype Box [value _meta]
  clojure.lang.IObj
  (meta [_] _meta)
  (withMeta [_ m] (Box. value m))
  clojure.lang.IDeref
  (deref [_] value)
  Object
  (toString [this]
    (str (.getName (class this))
         ": "
         (pr-str value))))

(defmethod print-method Box [o, ^Writer w]
  (.write w "#<")
  (.write w (.getName (class o)))
  (.write w ": ")
  (.write w (-> o deref pr-str))
  (.write w ">"))

(defn box
  ([value] (box value nil))
  ([value meta] (Box. value meta)))

And here's some example usage:

user> (def boxed (box (->> (range 5)
                        (map byte)
                        (byte-array))
                      {:stuff :foo}))
#<Var@1acd39b: #<Box@c50aa1: #>>
user> @boxed
[0, 1, 2, 3, 4]
user> (meta boxed)
{:stuff :foo}
user> (meta (with-meta boxed {:stuff :bar}))
{:stuff :bar}

This is the simplest way I can think of to put metadata on a byte array (reify doesn't work with clojure.lang.IObj and records include more unrelated functionality).

Another option (and perhaps simpler depending on the context) would be to store the byte array in a map, with the metadata either right alongside it or as actual metadata.

like image 116
jbm Avatar answered Sep 28 '22 01:09

jbm