programmatically create new namespace and put vars in there from another namespace - clojure

Say I am in test.core and I want to create test.new-ns and stick a var called new-method in there. Is there a way to do that without leaving test.core?
This is what I want to do:
(ns test.core)
(create-ns 'test.new-ns)
(put-in-ns 'test.new-ns 'new-method {:meta 1} {:value 1})
*ns* ;=> test.core
test.new-ns/new-method ;;=> {:value 1}
(meta #'test.new-ns/new-method) ;; => {:meta 1}

create-ns actually exists in clojure.core and has exactly this signature.
As for put-in-ns, that's called intern; also, rather than accepting a metadata map as a separate argument, it transfers any metadata attached to the "name" symbol to the Var:
(intern 'test.new-ns (with-meta 'new-method {:meta 1}) {:value 1})
Reader meta works too, as long as you put it "inside the quote":
(intern 'test.new-ns ' ^{:meta 1} new-method {:value 1})

I believe you're looking for intern.
Finds or creates a var named by the symbol name in the namespace
ns (which can be a symbol or a namespace), setting its root binding
to val if supplied. The namespace must exist. The var will adopt any
metadata from the name symbol. Returns the var.
So for your example, it would go a little something like this:
(ns test.core)
(create-ns 'test.new-ns)
(intern 'test.new-ns 'new-method {:value 1})

Related

Clojure function self reference to get own metadata

When I attach some metadata to a function and then call it I am not able to access those metadata within that function
(let [I (fn I [x] (println I) (println (meta I)))]
(let [f (with-meta I {:rr 5})]
(println I)
(println f)
(f I)))
I see that the self reference from within the function is not the function instance actually invoked and thus no metadata is available through that self reference. I need the self reference to give me the function instance actually invoked to access those metadata
I think that the problem is that your conflating the value of the function and the identity of the function together. It's a thing many other languages do so it's natural when you're learning Clojure. In your example, I has a reference to itself, and looks up the metadata from that reference, which returns nil. You then create f which is the same as I, but with some metadata. So when you run f it looks up the metadata on I and returns nil. Defining f doesn't change I at all, it just creates a new thing in terms of the old thing. If you want to change something you need to introduce a reference type that you can change. There are several of these, but usually to store functions you'd use a Var (see here for reference)
(defn i [] (meta i))
(i) ;;=> nil
(alter-var-root #'i with-meta {:rr 5})
(i) ;;=> {:rr 5}
Here we define a function in the current namespace called i which just returns it's own metadata. We call it to get nil. Then we alter the global reference with some new metadata, and call it again.
If you wanted a more lexically scoped example, you could use an atom as below:
(let [i (atom nil)
f (fn [] (meta #i))]
(reset! i f)
(prn 'before '>> (#i))
(swap! i with-meta {:rr 5})
(prn 'after '>> (#i)))
However, other than learning how these things fit together, I'm not sure what the goal is. It's probably a bad idea to try and use these structures in a real program that you plan on maintaining.
Rather accidentally, I found a trick that enables functions to read it own metadata. It appears, the Clojure compiler generates metadata support code differently when the original function definition has custom metadata. If it is present, (meta fn-name) works inside the body of the function, otherwise it does not. For example, the following produces the result desired by the OP:
*clojure-version*
;;=> {:major 1, :minor 10, :incremental 0, :qualifier nil}
(let [f1 ^{:foo true} (fn f [] (meta f))
f2 (with-meta f1 {:bar true})]
(prn (f1))
(prn (f2)))
;;=> {:foo true}
;;=> {:bar true}
;;=> nil
We can examine the code generated for a function without the metadata in the original definition - there is just the invoke method
(require '[clojure.pprint :as p])
(let [ff (fn f [] (meta f))]
(p/pprint (seq (.getDeclaredMethods (class ff)))))
;;=> (#object[java.lang.reflect.Method 0x2b56b137 "public java.lang.Object user$eval2171$f__2172.invoke()"])
;;=> nil
And when the metadata is present, additional methods (meta and withMeta) are generated to deal with the metadata.
(let [ff ^:foo (fn f [] (meta f))]
(p/pprint (seq (.getDeclaredMethods (class ff)))))
;;=> (#object[java.lang.reflect.Method 0x3983bd83 "public clojure.lang.IObj user$eval2175$f__2176.withMeta(clojure.lang.IPersistentMap)"]
;;=> #object[java.lang.reflect.Method 0x547d182d "public clojure.lang.IPersistentMap user$eval2175$f__2176.meta()"]
;;=> #object[java.lang.reflect.Method 0x62c3d0fe "public java.lang.Object user$eval2175$f__2176.invoke()"])
;;=> nil
Welcome to Clojure, #xstreamer!
I'm going to suggest something different from what (precisely) you're asking for. I don't know how querying the function's metadata from within the function should work, really. So I'm going to suggest defining the function first, and redefining the function metadata afterwards. This is fairly simple in Clojure.
(defn f
"Boring doc"
[])
(meta #'f)
;; => {:arglists ([]),
;; :doc "Boring doc",
;; :line 32,
;; :column 1,
;; :file "C:/Users/teodorlu/IdeaProjects/th-scratch/src/th/play/core.clj",
;; :name f,
;; :ns #object[clojure.lang.Namespace 0x3b402f0c "th.play.core"]}
Now, redefine it!
(alter-meta! #'f assoc :rr 5)
(meta #'f)
;; => {:arglists ([]),
;; :doc "Boring doc",
;; :line 32,
;; :column 1,
;; :file "C:/Users/teodorlu/IdeaProjects/th-scratch/src/th/play/core.clj",
;; :name f,
;; :ns #object[clojure.lang.Namespace 0x3b402f0c "th.play.core"],
;; :rr 5}
Where assoc sets a value in a map.
(assoc {} :rr 5)
;; {:rr 5}
(assoc {:some :stuff} :more :stuff)
;; {:some :stuff, :more :stuff}
References
If you're confused by the #'f, this is how you get the var representing the binding of f, instead of just the value it refers to. For more information about vars and how to use them, refer to the official reference on vars and the less terse guide from 8th light.

Accessing argument's metadata in Clojure macro

Is there a way to retrieve the metadata of the arguments inside a clojure macro without using eval? The only thing I could come up with so far is this:
(def ^{:a :b} my-var)
(defmacro my-macro [s] (prn (eval `(meta (var ~s)))))
(my-macro my-var)
;; Prints {:a :b, :name my-var, ...}
I ended up finding a solution:
(def ^{:a :b} my-var)
(defmacro my-macro [s] (prn (meta (resolve s))))
(my-macro my-var)
;; Prints {:a :b, :name my-var, ...}
So the key part here is to use resolve function to get the var associated to the symbol.

how to get the name string from a variable or function?

I would like to get the name of a variable as a string in Clojure.
However, unlike in this question, I would get the name of the original binding (not sure if the terminology is correct, so please see my example below).
(def sample-data1 {:data 1})
(def sample-data2 {:data 2})
(def sample-data3 {:data 3})
(doseq
[my-var [sample-data1 sample-data2 sample-data3]]
(println (name 'my-var)))
In this case, instead of printing
my-var
my-var
my-var
I would like to have :
sample-data1
sample-data2
sample-data3
How do I do that in Clojure ?
Note : This is probably not the prettiest thing to do in a real app. But my question is about if this is this possible.
To clarify : this is for prototyping purposes. In this specific case instead of printing I am filling a (postgres) database with fake data that I write by hand in variables, and I'd like to track where my variable end up without writing too much code.
def creates a var with the same name as the name of the symbol supplied as def first parameter. Var in clojure differs from what we usually meant by variable whereas a variable usually can be visualized as a box that contains a value and a var is something that points to a value.
From your example, (here, I am in user namespace)
user> (def sample-data1 {:data 1})
#'user/sample-data1
clojure creates a #'user/sample-data1 var in user namespace which points to {:data 1} value. You can get the value back from that newly create var by deref-ing it using deref or # shorthand.
user> (deref #'user/sample-data1)
{:data 1}
user> ##'user/sample-data1
{:data 1}
or if you evaluate a symbol, clojure looks up for a var in the current namespace and returns the value pointed by that var.
user> sample-data1
{:data 1}
you can get a var from a symbol by using var for #' shorthand.
user> (var sample-data1)
#'user/sample-data1
user> #'sample-data1
#'user/sample-data1
So, you want the name of the var. The name of the var is contained inside the var's meta data which can be accessed using meta applied to a var.
user> (meta #'sample-data1)
{:line 1, :column 1, :file "/tmp/form-init3246148490151701909.clj",
:name sample-data1, :ns #object[clojure.lang.Namespace 0x39ba2c26 "user"]}
Above, you can see that the name of the var is located by :name key.
so, you can get the name of a var from its metadata.
user=> (:name (meta #'sample-data1))
sample-data1
I prefer not to have too many nested parenthesis, so I use thread-first macro ->
user=> (-> #'sample-data1 meta :name)
sample-data1
the answer
So back to your question, you need the sample-data[1-3] vars and their metadata to get their name.
(def sample-data1 {:data 1})
(def sample-data2 {:data 2})
(def sample-data3 {:data 3})
(doseq
[my-var [#'sample-data1 (var sample-data2) #'sample-data3]]
(println (-> my-var meta :name)))
and the result is
sample-data1
sample-data2
sample-data3
nil

Using Clojure's data structure with MapDB

I tried to use directly Clojure's hashmap with MapDB and ran into weird behaviour. I checked Clojure and MapDB sources and couldn't understand the problem.
First everything looks fine:
lein try org.mapdb/mapdb "1.0.6"
; defining a db for the first time
(import [org.mapdb DB DBMaker])
(defonce db (-> (DBMaker/newFileDB (java.io.File. "/tmp/mapdb"))
.closeOnJvmShutdown
.compressionEnable
.make))
(defonce fruits (.getTreeMap db "fruits-store"))
(do (.put fruits :banana {:qty 2}) (.commit db))
(get fruits :banana)
=> {:qty 2}
(:qty (get fruits :banana))
=> 2
(first (keys (get fruits :banana)))
=> :qty
(= :qty (first (keys (get fruits :banana))))
=> true
CTRL-D
=> Bye for now!
Then I try to access the data again:
lein try org.mapdb/mapdb "1.0.6"
; loading previsously created db
(import [org.mapdb DB DBMaker])
(defonce db (-> (DBMaker/newFileDB (java.io.File. "/tmp/mapdb"))
.closeOnJvmShutdown
.compressionEnable
.make))
(defonce fruits (.getTreeMap db "fruits-store"))
(get fruits :banana)
=> {:qty 2}
(:qty (get fruits :banana))
=> nil
(first (keys (get fruits :banana)))
=> :qty
(= :qty (first (keys (get fruits :banana))))
=> false
(class (first (keys (get fruits :banana))))
=> clojure.lang.Keyword
How come the same keyword be different with respect to = ?
Is there some weird reference problem happening ?
The problem is caused by the way equality of keywords works. Looking at the
implementation of the = function we see that since keywords are not
clojure.lang.Number or clojure.lang.IPersistentCollection their equality is
determined in terms of the Object.equals method. Skimming the source of
clojure.lang.Keyword we learn that keywords don't not override
Object.equals and therefore two keywords are equal iff they are the same
object.
The default serializer of MapDB is org.mapdb.SerializerPojo, a subclass of
org.mapdb.SerializerBase. In its documentation we can read that
it's a
Serializer which uses ‘header byte’ to serialize/deserialize most of classes
from ‘java.lang’ and ‘java.util’ packages.
Unfortunately, it doesn't work that well with clojure.lang classes; It doesn't
preserve identity of keywords, thus breaking equality.
In order to fix it let's attempt to write our own serializer using the
EDN format—alternatively, you could consider, say, Nippy—and use
it in our MapDB.
(require '[clojure.edn :as edn])
(deftype EDNSeralizer []
;; See docs of org.mapdb.Serializer for semantics.
org.mapdb.Serializer
(fixedSize [_]
-1)
(serialize [_ out obj]
(.writeUTF out (pr-str obj)))
(deserialize [_ in available]
(edn/read-string (.readUTF in)))
;; MapDB expects serializers to be serializable.
java.io.Serializable)
(def edn-serializer (EDNSeralizer.))
(import [org.mapdb DB DBMaker])
(def db (.. (DBMaker/newFileDB (java.io.File. "/tmp/mapdb"))
closeOnJvmShutdown
compressionEnable
make))
(def more-fruits (.. db
(createTreeMap "more-fruits")
(valueSerializer (EDNSeralizer.))
(makeOrGet)))
(.put more-fruits :banana {:qty 2})
(.commit db)
Once the more-fruits tree map is reopened in a JVM with EDNSeralizer defined
the :qty object stored inside will be the same object as any other :qty
instance. As a result equality checks will work properly.

Applying var or #' to a list of functions in Clojure

I'm trying to read metadata for a collection of functions in Clojure, but the var or reader special forms do not work unless they are directly dealing with the symbol.
; this works
(var my-fn)
; this doesn't
(defn val-it [x] (var x))
(val-it my-fn)
Is there any way to get this to work within the scope of another function?
resolve returns the Var or class object corresponding the given symbol in the context of the current namespace. ns-resolve allows you to specify which namespace to resolve the symbol in.
(resolve 'my-fn)
;= #'some.ns/my-fn
If the symbol cannot be resolved to a Var, nil is returned.
(var my-fn) does deal directly with the symbol because it is a special form (the reader receives the form unevaluated).
The metadata you want to read is stored in the var object, not in the function object.
Thus your goal, to read metadata from a list of function objects, is only achievable by traversing all existing vars and comparing their value by equality. I'd only recommend it if the function objects are the only way to start.
(defn meta-of
"Returns a hashmap mapping the function objects in fn-objs to
a set of metadata of vars containing it."
[fn-objs]
(let [fn-objs (set fn-objs)]
(reduce (fn [acc ns]
(reduce (fn [acc var]
(let [val (var-get var)]
(cond-> acc
(contains? fn-objs val)
(update-in [val] (fnil conj #{}) (meta var)))))
acc
(vals (ns-interns ns)))) {} (all-ns))))
(def foo inc) ;; Now there are two vars that have the inc function as their value
(meta-of [inc])
{#<core$inc clojure.core$inc#66d7e31d> ;; <- function object
#{{:ns #<Namespace clojure.core>, ;; <- metadata in clojure.core namespace
:name inc,
:file "clojure/core.clj",
:column 1,
:line 881,
:arglists ([x]),
:added "1.2",
:inline #<core$inc__inliner clojure.core$inc__inliner#24f87069>,
:doc
"Returns a number one greater than num. Does not auto-promote\n longs, will throw on overflow. See also: inc'"}
{:ns #<Namespace user>, ;; <- metadata in user namespace
:name foo,
:file "/tmp/form-init1078564431656334911.clj",
:column 1,
:line 1}}}