I'm trying to create a macro that makes a Clojure deftypeand which requires type hints to be generated. I currently have some test code:
(defmacro test-macro [n]
(let [obj-sym (gensym "obj")
p0 (with-meta 'p0 {:tag java.lang.Object})
p1 (with-meta 'p1 {:tag java.lang.Integer/TYPE})
r0 (with-meta 'remove {:tag java.lang.Boolean/TYPE})
r1 (with-meta 'remove {:tag java.lang.Object})]
`(deftype ~n [~obj-sym]
java.util.List
(~r0 [_ ~p0] (.remove ~obj-sym ~p0))
(~r1 [_ ~p1] (.remove ~obj-sym ~p1)))))
When it returns:
(test-macro test-it)
;clojure.lang.Compiler$CompilerException: java.lang.IllegalArgumentException: Must hint overloaded method: remove, ...
As a guide, it should produce something equivalent to:
(clojure.core/deftype ThisWorks [obj-5546]
java.util.List
(#^"boolean" remove [_ ^java.lang.Object p0-object] (.remove obj-5546 p0-object))
(^{:tag "java.lang.Object"} remove [_ ^int p0-int] (.remove obj-5546 p0-int)))
It looks like I am type hinting the wrong thing, or the meta data isn't being passed. Other than a fix for the immediate problem, bonus points if you can help out with the more general "meta" problem: how to debug a macro which manipulates metadata as macroexpand isn't very useful here..
Thanks
The :tag metadata is supposed to be a symbol, not a class object (since, after all, a symbol is all you can type as code in a non-macro situation: I can't embed the Class object int itself in my code!). So rather than Integer/TYPE, you just want 'int, and similarly for all your other typehints.
Related
guys,
look at the code first:
(defmacro map-remove- [v w]
`(dosync
(ref-set ~v (dissoc #~v (keyword ~w)))))
(defmacro set-remove- [v w]
`(dosync
(ref-set ~v (disj #~v ~w))))
(defmacro clean- [v]
`(dosync
(ref-set ~v (empty #~v))))
They work fine now , but I want write a more general macro to combine "map-remove-" and "set-remove-" in one. according my C/Java experience I chose "case" but obviously the case can't use in macro defination cause "The test-constants are not evaluated. They must be compile-time literals", the following code won't work:
(defmacro [x]
(case (type x) ;;;;;;;;;;; This will never work!directly reach to default clause
....))
anybody has any suggestion? very appreciate.
You can use the functions map? and set? to test whether a value is a map or a set respectively.
I'm not sure I have enough perspective on what you're trying to do here though - I've substituted a macro instead of a function, because I can't see the necessity for a macro in the sample you've given.
;; Create a function to remove in a different way when given a map/set and a string
(defn remove- [v w]
(dosync
(cond
(map? #v)
(ref-set v (dissoc #v (keyword w)))
(set? #v)
(ref-set v (disj #v w)))))
;; Set up some mutable refs
(def m (ref {:a 1 :b 2}))
(def s (ref #{"a" "b" "c"}))
;; Remove from the refs
(remove- m "b") => {:a 1}
(remove- s "b") => #{"a" "c"}
On a side note - are you sure you need to use refs? I know that coming from a C/Java background, mutability is the default, but I've never actually had to use it in Clojure so far. Clojure places a lot of emphasis on immutability, and most things can be done (often very elegantly) just by using functions on immutable values.
I'm trying to schedule a Clojure function using Executors.newSingleThreadScheduledExecutor(). The annoyance is that calling .get() on the resulting ScheduledFutureTask returns nil instead of the function's result.
I'm taking Mr Hickey's implementation of futures as the model.
(ns my.ns
(:import (java.util.concurrent Executors ThreadFactory TimeUnit)))
(def ^:private thread-pool-scheduler (atom nil))
(def ^:private thread-pool-counter (agent 0))
(defn- get-and-increment-thread-id []
(-> thread-pool-counter (send inc) deref))
(def ^:private thread-factory
(reify ThreadFactory
(newThread [this f]
(let [thread (Thread. f)]
(.setName thread (format "clojure-scheduled-future-thread-pool-%d"
(get-and-increment-thread-id)))
thread))))
(defn scheduled-future-call [^Callable f ^long delay ^TimeUnit unit]
(.schedule (scheduled-futures-executor) (bound-fn* f) delay unit))
(defn start-scheduled-futures-executor! []
(reset! thread-pool-scheduler
(Executors/newSingleThreadScheduledExecutor thread-factory)))
(defn scheduled-futures-executor []
(or #thread-pool-scheduler
(start-scheduled-futures-executor!)))
Everything works, and side-effects fire when appropriate (e.g. scheduling #(println "ok")).
However, calling the get() method of the resulting ScheduledFutureTask always gives me nil
(e.g. scheduling #(+ 5 5)).
I tried extending Callable explicitly, tried omitting bound-fn*, but the result is the same:
(defprotocol ISchedule
(schedule [this delay time-unit]))
(extend Callable
ISchedule
{:schedule (fn [this delay time-unit]
(.schedule (scheduled-futures-executor) this delay time-unit))})
My intuition is that the ScheduledExecutorService is choosing schedule(Runnable, long, TimeUnit) over schedule(Callable, long, TimeUnit), but shouldn't type hints fix that?
Many, many thanks for any help or tips!
My intuition is that the ScheduledExecutorService is choosing schedule(Runnable, long, TimeUnit) over schedule(Callable, long, TimeUnit),
I think you're right, only I reified Callable and it worked properly. (I also added Callable to the list of classes in the import statement).
EDIT: I also removed the call to bound-fn*
Check it out:
(defn make-callable [f] (reify Callable (call [this] (f))))
(def cat (make-callable (fn [] (println "meeow") "i am a cat")))
(def who-are-you? (scheduled-future-call cat 2 TimeUnit/SECONDS))
(println "Tell me who you are!\n\t" (.get who-are-you?))
outputs:
meeow
Tell me who you are!
i am a cat
The ^Callable hint on f does you no good, because you just call bound-fn anyway, whose result is not type-hinted. You need to hint the thing you actually pass to .schedule. More importantly, you need to hint the target object itself (the executor), as the compiler will (quite reasonably) ignore any hints on arguments if the target object is not hinted: it has to do reflection anyway if it doesn't know the type of the target!
So, hint both of those things in a let-binding1 and you should be fine. You might need to hint all the rest of the arguments as well for disambiguation, but I don't think so.
1 Note: do not hint the expressions generating them, eg ^Callable (bound-fn f). That usually works, but sometimes doesn't, in scenarios that are complicated to explain. Best to just avoid that scenario.
The macro, transform!, as defined below seems to work for => (transform! ["foo" 1 2 3]). The purpose is to take in a list, with the first element being a string that represents a function in the namespace. Then wrapping everything into swap!.
The problem is that transform! doesn't work for => (transform! coll), where (def coll ["foo" 1 2 3]). I am getting this mystery exception:
#<UnsupportedOperationException java.lang.UnsupportedOperationException: nth not supported on this type: Symbol>
The function:
(defmacro transform!
" Takes string input and update data with corresponding command function.
"
[[f & args]] ;; note double brackets
`(swap! *image* ~(ns-resolve *ns* (symbol f)) ~#args))
I find it strange that it works for one case and not the other.
Macros work at compile-time and operate on code, not on runtime data. In the case of (transform! coll), the macro is being passed a single, unevaluated argument: the symbol coll.
You don't actually need a macro; a regular function will suffice:
(defn transform! [[f & args]]
(apply swap! *image* (resolve (symbol f)) args)))
Resolving vars at runtime could be considered a code smell, so think about whether you really need to do it.
You're passing a symbol to the macro, namely coll. It will try to pull that symbol apart according to the destructuring statement [f & args], which won't be possible of course.
You can also use (resolve symbol) instead of (ns-resolve *ns* symbol).
I am currently developing a small CMS using the wonderful Enlive as templating engine. Enlive has a macro called at that takes a node (a map) specifying the HTML snippet and an arbitrary number of tuples each consisting of a selector (a vector) and a transformation (a closure).
(at a-node
[:a :selector] a-transformation
[:another :selector] another-transformation
...)
Now I want to generate the tuples depending upon incoming data/context. I have tried a lot of different things without success. For example
(let [this (repository/u "http://example.com/ACMECorp")
statements (repository/find-by-subject this)
context {:depth 1}]
`(at (snippet-for 'this 'context)
[root] (set-attr :about (str 'this))
~#(loop [rules []
st statements]
(if-not (seq st)
rules
(recur (conj rules
`[:> (attr= :property ~(str (repository/predicate (first st))))]
`(content (renderit ~(repository/object (first st)) 'context)))
(rest st))))))
Any help is highly appreciated.
-Jochen
Clojure is a Lisp, so you can always fallback to building the code you'd want as a list, and call eval on it. I'm not 100% sure about the code you gave, but I'd guess you just want to enclose your whole syntax-quote in an eval call.
(let [this (repository/u "http://example.com/ACMECorp")
statements (repository/find-by-subject this)
context {:depth 1}]
(eval `(at (snippet-for 'this 'context)
[root] (set-attr :about (str 'this))
~#(loop [rules []
st statements]
(if-not (seq st)
rules
(recur (conj rules
`[:> (attr= :property ~(str (repository/predicate (first st))))]
`(content (renderit ~(repository/object (first st)) 'context)))
(rest st)))))))
Not sure if they are interchangeable, but take a look at the at* function. Seems to me that your problem is at being a macro.
EDIT: They're not. Call it like this:
(at* a-node
[[:a :selector] a-transformation
[:another :selector] another-transformation
...])
As a follow-up to my previous question, I am trying to write a macro that builds a defprotocol:
(build-protocol AProtocol
[(a-method [this]) (b-method [this that])]
(map (fn [name] `(~(symbol (str name "-method")) [~'this ~'that ~'the-other]))
["foo" "bar" "baz"])
(map (fn [name] `(~(symbol (str name "-method")) [~'_]))
["hello" "goodbye"]))
should expand to
(defprotocol AProtocol
(a-method [this])
(b-method [this that])
(foo-method [this that the-other])
(bar-method [this that the-other])
(baz-method [this that the-other])
(hello-fn [_])
(goodbye-fn [_]))
My attempt:
(defmacro build-protocol [name simple & complex]
`(defprotocol ~name ~#simple
~#(loop [complex complex ret []]
(if (seq complex)
(recur (rest complex) (into ret (eval (first complex))))
ret))))
and expansion (macroexpand-1 '(...)):
(clojure.core/defprotocol AProtocol
(a-method [this])
(b-method [this that])
(foo-method [this that the-other])
(bar-method [this that the-other])
(baz-method [this that the-other])
(hello-method [_])
(goodbye-method [_]))
I'm not really happy about the eval. Also, the map expressions are pretty ugly. Is there a better way? Any and all comments welcome.
Once I get this working, I'm going to do a similar macro for (build-reify ...). I'm writing a rather large Swing application and have several components (JButtons, JCheckBoxes, etc.) that have almost identical method signatures and actions.
I think you're doing it upside down. Specify the "-method" stuff first, wrapped in a container of some kind so build-protocol knows what's what, and let it do the map inside the macro. e.g:
(build-protocol AProtocol
{[this that whatever] [foo bar baz],
[_] [hello goodbye]}
; a-method and b-method...
)