I'm currently implementing multiple types with the same protocol as the basis and would like to reduce the number of files one would need to include in the namespace in order to use them. To give an example:
basetype.clj
(defprotocol Base
(do-something [obj]))
(deftype Basetype [obj]
...
Base
(do-something [obj] something-something))
second_type.clj
(ns project.second-type
(:use project.basetype))
(deftype DifferentType [obj]
...
Base
(do-something [obj] something-slightly-different))
What I did achieve is that everything built for Basetype also works with DifferentType. However, I'd like to access the function do-something simply by including second_type.clj in a namespace instead of including both. Is there a way to achieve this?
as i mentioned in my comment, you should be able to reexport any values from any namespace.
you could make up simple function like this:
(defn reexport [from-ns name]
(ns-unmap *ns* name)
(intern *ns* name #(ns-resolve from-ns name)))
(reexport 'project.basetype 'do-something)
or to reexport all the values from the given ns:
(defn reexport-all [from-ns]
(run! (partial reexport from-ns) (map first (ns-publics from-ns))))
(reexport-all 'project.basetype)
in repl:
user> (ns x)
nil
x> (defn f [v] (inc v))
#'x/f
x> (ns y)
nil
y> (user/reexport 'x 'f)
#'y/f
y> (in-ns 'user)
#namespace[user]
user> (y/f 10)
11
user> (in-ns 'y)
#namespace[y]
y> (defn f2 [v] (dec v))
#'y/f2
y> (ns z)
nil
z> (user/reexport-all 'y)
nil
z> (in-ns 'user)
#namespace[user]
user> (z/f 1)
2
user> (z/f2 1)
0
Related
I want to achieve to return a namespace resolved symbol in a macro that has recently defined the symbol itself:
(ns my-namespace)
(defmacro def&resolve [a b]
`(do
(def ~a 12)
(def ~b ~(resolve a))))
(def&resolve foo bar)
bar ;=> nil
In the example bar returns nil. I however, want it to return my-namespace.foo. I know this is not working since at the time resolve is called, a isn't defined yet. I need a to be namespace-resolved at macro-expansion time for my use case [1], however.
In the next run I wanted to declare a at macro expansion time (does that even make sense?) and, thus, force that it is present in the current ns when calling resolve.
(defmacro def&resolve [a b]
(declare a)
`(do (def ~a 12)
(def ~b ~(resolve a))))
(def&resolve foo bar)
bar ;=> nil
Doesn't work either.
How can I def something and at the very macro expansion namespace resolve it?
[1] My use case is the following: I want to define a bundle of functions and add it to the meta information of a def-binding (thus, I need it at macro expansion time). Currently, I only store the symbols, without the namespace the functions were defined in.
(ns another-namespace)
(defmacro def&resolve [a b]
`(do
(def ~a 12)
(def ~b (resolve '~a))))
(macroexpand-1 '(def&resolve foo bar))
#=> (do (def foo 12) (def bar (clojure.core/resolve (quote foo))))
(def&resolve foo bar)
bar
#=> #'another-namespace/foo
since the var will be def'ed/created at run time, once the macro has finished it's job and gone away, the macro can instead predict what the var will be named and create the symbol directly rather than making a round trip through the namespace and back
Let's do it manually first
user> (def foo)
#'user/foo
user> (resolve 'foo)
#'user/foo
that looks right, now let's do it by creating the symbol:
user> (symbol (str *ns* "/" "foo"))
user/foo
and copy that into the macro definition:
user> (defmacro def&resolve [a b]
`(do
(def ~a 12)
(def ~b ~(symbol (str *ns* "/" "foo")))))
#'user/def&resolve
and test it out
user> (def&resolve foo bar)
#'user/bar
user> bar
12
This method is preferable to the approach of using intern to create the symbol in the namespace using a dummy value, at macro expand time, then resolveing it also at macro expansion time. Resulting in the same value. The advantage of this approach is that it does make resolve work at macro expand time as in your original question
user> (do (intern *ns* 'a :dummy-value)
(resolve 'a))
#'user/a
though i recommend going with the symbol generation approach.
Nesting of syntax quote helps, with additional quoting of ~a:
(defmacro def&resolve
[a b]
`(do
(def ~a 12)
(def ~b ~`(resolve '~a))))
#'test-project.core/def&resolve
test-project.core=> (macroexpand '(def&resolve foo bar))
(do (def foo 12) (def bar (clojure.core/resolve (quote foo))))
test-project.core=> (def&resolve foo bar)
#'test-project.core/bar
test-project.core=> foo
12
test-project.core=> bar
#'test-project.core/foo
If you actually want to get value of foo into the bar, then you have to deref (#) var you get by resolving:
(defmacro def&resolve
[a b]
`(do
(def ~a 12)
(def ~b #~`(resolve '~a))))
test-project.core=> (def&resolve foo bar)
#'test-project.core/bar
test-project.core=> bar
12
(map (fn [x]
(let [username (or (:f_username x) nil)
sites_names (SITES-NAMES username)
x (assoc x :sites sites_names)]
x)) my-rows)
In the code above: SITES-NAMES gives me an arity exception. However
if I call it (SITES-NAMES "theuser") it works. Why is this the case
if username evaluates as an example to "theuser".
I don't know why this is happening, but here are a few tips:
1) Make your anonymous function a top-level function, as such:
(defn add-site [site-names {:keys [f-username] :as x}]
(assoc x :sites (get site-names f-username)))
Notice how I name the vars, refer to https://github.com/bbatsov/clojure-style-guide for more info on naming and other neat stuff.
2) Now you can change your call to map with
(map (partial add-site site-names) my-rows)
This lets you play around with the add-site function at the REPL like so:
user> (add-site {"hector" "www.hector.com"} {:f-username "hector"})
;; => {:f-username "hector", :sites "www.hector.com"}
You might want to read this as well:
https://stuartsierra.com/2015/08/10/clojure-donts-redundant-map
The following works in the repl:
(defprotocol MyProtocol
(foo [this]))
(deftype A []
MyProtocol
(foo [this] "a"))
(deftype B []
MyProtocol
(foo [this] "b"))
(deftype C []
MyProtocol
(foo [this] (str (foo (A.)) (foo (B.)))))
When I try to move each instance to a separate file to reduce coupling, then I get the following error on C: "Unable to resolve symbol: foo in this context"
Sample layout:
;; my_protocol.clj
(ns my-protocol)
(defprotocol MyProtocol
(foo [this]))
;; type_a.clj
(ns type-a
(:require my-protocol :refer [MyProtocol])
(deftype A []
MyProtocol
(foo [this] "a"))
;; type_b.clj
(ns type-b
(:require my-protocol :refer [MyProtocol])
(deftype B []
MyProtocol
(foo [this] "b"))
;; type_c.clj
(ns type-c
(:import [type_a A]
[type_b B])
(:require my-protocol :refer [MyProtocol])
(deftype C []
MyProtocol
(foo [this] (str (foo (A.)) (foo (B.)))))
(ns type-a
(:require my-protocol :refer [MyProtocol])
You refer to the protocol, but never to foo, so when you attempt to call foo the compiler doesn't know what you mean. Instead write:
(ns type-a
(:require my-protocol :refer [MyProtocol foo])
I have the following record type that I am trying to test:
(defrecord FirstOrderState [datum matrix]
State
;; implementation goes here ...
)
I am trying to branch based on the above type, but am not getting the results I need
(def state (->FirstOrderState datum matrix))
(= (type state) composer.algorithm.markov.state.FirstOrderState)
=> false
However, looking at the type of state confirms that it should match:
(type state)
=> composer.algorithm.markov.state.FirstOrderState
This seems like it should work, as a similar check results in true:
(= (type []) clojure.lang.PersistentVector)
=> true
What is it that I am missing here? Using the below hack provides a solution, but not very elegant:
(= (str (type state)) (str composer.algorithm.markov.state.FirstOrderState))
=> true
My first guess would be that you have reloaded the namespace containing the definition of the record type and that state is defined elsewhere (possibly at the REPL), and so composer.algorithm.markov.state.FirstOrderState now refers to a different class from the one it used to at the time when state was created.
Demo at the REPL:
user=> (defrecord Foo [])
user.Foo
user=> (def foo (->Foo))
#'user/foo
user=> (= (type foo) Foo)
true
user=> (defrecord Foo [])
user.Foo
user=> (= (type foo) Foo)
false
I encountered something like this in a program:
(defonce foo nil)
(alter-var-root #'foo (constantly 4))
Since the code above uses constantly, is there any reason to prefer it to a simple def, like below?
(def foo 4)
Is it just to make it more consistent with the defonce, or there are downsides to using def?
(ns banana)
(defonce foo nil)
(ns user)
(use 'banana)
foo ;=> nil
(alter-var-root #'foo (constantly 42))
foo ;=> 42
(def foo 50)
CompilerException java.lang.IllegalStateException: foo already refers to: #'banana/foo in namespace: user