I'm trying to define a protocol in Clojure 1.4 with primitive arguments (so that I can avoid unnecessary primitive boxing in performance-sensitive code):
(defprotocol A
(foo [a ^long x]))
(extend-type java.lang.String A
(foo [s ^long x] (.charAt s x)))
This look like it works OK but fails with an exception when I try to use it:
(foo "abracadarbra" 3)
=> ClassCastException XXXX cannot be cast to clojure.lang.IFn$OLO
What am I doing wrong?
After some further reasearch it appears that protocols do not yet support primitive type hints (as of Clojure 1.4). See e.g. https://groups.google.com/d/topic/clojure-dev/HxBqIewc494/discussion
Alternatives seem to be:
Write regular functions with primitive hints. You lose polymorphism.
Use a Java interface (you can use reify to build instances in Clojure)
take the type hint out of the defprotocol and leave it in the extend-type
(defprotocol A
(foo [a x]))
(extend-type java.lang.String A
(foo [s ^Long x] (.charAt s x)))
nil
core> (foo "abracadarbra" 3)
\a
or you can change the type hint like so:
(defprotocol A
(foo [a ^Long/TYPE x]))
(extend-type java.lang.String A
(foo [s ^long x] (.charAt s x)))
nil
core> (foo "abracadarbra" 3)
\a
this still produces no reflection warnings without the hint in the defprotocol
EDIT:
(extend-type java.lang.String A
(foo [s ^Long x] (type x)))
nil
core> (foo "abracadarbra" 3)
java.lang.Long
Related
My goal is a function/macro that works like this:
(def f (polymorphic-fn
java.lang.Long (fn [a] (inc a))
java.lang.String (fn [a] (str a "x"))))
(f 1) ;; => 2
(f "abc") ;; => "abcx"
Since the type-based dispatch of protocols has the best performance I was thinking to create an 'anonymous' protocol for the 'fused' function with a macro like this:
(defmacro polymorphic-fn
[& pairs]
(let [proto (gensym)
method (gensym)
extends (for [[type handler] pairs]
`(extend ~type ~proto {(keyword ~method) ~handler}))]
`(do
(defprotocol ~proto (~method [e#]))
~#extends
~method)))
This produces the error: Unable to resolve symbol: G__18707.
Is there a way to return the 'anonymous' method, or is there a better way to implement such a function?
The problem is that the defprotocol will generate code that will intern the protocol methods. Ie. after macroexpansion, the symbols for your defined method is still not known to the compiler. Thus, the compilation fails and will barf that the symbol is unknown.
Many other def...'s will generate a macro "call" that will intern the symbol during macro expansion (and thus the compiler will remain happy).
To fix it you can just declare it beforehand. This works since declare is macro, will get expanded and the compiler will be happy:
(defmacro polymorphic-fn
[& pairs]
(let [proto (gensym "proto")
method (gensym "prot-method-")
extends (for [[type handler] (partition 2 pairs)]
`(extend ~type ~proto {~(keyword (str method)) ~handler}))]
`(do
(declare ~method)
(defprotocol ~proto (~method [e#]))
~#extends
~method)))
Note: I also fixed the keyword call in this.
I think you just want to use regular protocols, along with extend-type:
(defprotocol Fooable
(foo [this]) )
(extend-type java.lang.Long
Fooable
(foo [some-long] (inc some-long)))
(extend-type java.lang.String
Fooable
(foo [any-string] (str any-string "-and-more")))
with result:
(foo 3) => 4
(foo "hello") => "hello-and-more"
It may be possible to use a macro to hide the protocol name by using an auto-gensym, but I don't see the point. Just ignore the protocol name 'Fooable' and you have the same result.
Also, be aware that parts of Clojure implementation create concrete Java classes behind the scenes, which may require a hard-coded name.
You could also mimic the protocol functionality by using a cond:
(defn bar [it]
(cond
(= (class it) java.lang.Long) (inc it)
(= (class it) java.lang.String) (str it "-and-more")))
(bar 7) => 8
(bar "farewell") => "farewell-and-more"
You could define a function to generate bar like you do with polymorphic-fn if you wanted.
I have a question regarding how to define functions/macros which call other macros or special forms but where one of the symbols passed in needs to be dynamic.
The simplest version of this question is described below:
We can define variables using def
(def x 0)
But what if we wanted the name x to be determined programmatically so that we could do the equivalent of?
(let [a 'b]
(our-def a 3)) => user/b
We could try to define a function
(defn defn2 [sym val]
(def sym val))
However it does not do what we want
(def2 'y 1) => #'user/sym
At first it seems like a macro works (even though it seems like it would be unnecessary)
(defmacro def3 [sym val]
`(def ~sym ~val))
(def3 z 2) => user/z
but it is just superficial, because we're really right back where we started with regular def.
(let [a 'b]
(def3 a 3)) => user/a
I can do it if I use eval, but it doesn't seem like eval should be necessary
(defn def4 [sym val]
(eval `(def ~sym ~val)))
(let [a 'b]
(def4 a 4)) => user/b
If there are other built-in commands that could achieve this particular example, they are not really what I am looking for since def is just to show a particular example. There are macros more complicated than def that I might want to call and not have to worry about how they were internally implemented.
First: The right way to do this is to use macro that starts with def... since this is the way people have been doing defs and is of little surprise to the user.
To answer you question: Use intern:
(def foo 'bar)
(intern *ns* foo :hi)
(pr bar) ;; => :hi
(intern *ns* foo :hi2)
(pr bar) ;; => :hi2
If you want to use macros do this:
(def z 'aa)
(defmacro def3 [sym val]
`(def ~(eval sym) ~val))
(def3 z 2)
(pr aa) ;; => 2
I am splitting part of my app into a library
The library functionality has certain dependencies which must be injected by the app. I have modeled this with a protocol
(defprotocol MyLibDependencies
(some-injected-capability [x]))
(defrecord Foo [y])
(defrecord Bar [y])
(defmulti render-response class)
(defmethod render-response Foo [val] {:ok (some-injected-capability (:y val))})
(defmethod render-response Bar [val] {:err (some-injected-capability (:y val))})
and here in the application I can provide an implementation:
(extend-type Object
MyLibDependencies
(some-injected-capability [x] (inc x)))
(comment
(render-response (Foo. 10)) ;; => {:ok 11}
(render-response (Bar. 10)) ;; => {:err 11}
)
This works, however it feels like an abuse of protocols, because I need neither polymorphic dispatch, nor does the injected function necessarily require an argument (the protocol requires at least one argument to dispatch against it's class). What are my options?
Note that the records Foo and Bar are library domain types, and the render-response method is also library domain. I don't necessarily care how I define them, but the abstractions they represent are library domain.
This is a bit closer to how you would typically see protocols used to provide functionality from client code to a library:
;; lib.clj
(defprotocol MyLibDependencies
(provide-status [this x])
(provide-response [this x]))
(defn render-response
[responder val]
{:status (provide-status responder val)
:code (provide-response responder val)})
;; client.clj
(defrecord Foo [y]
MyLibDependencies
(provide-status [this val]
(if (even? val)
:ok
:err))
(provide-response [this val]
(+ y val)))
(defrecord Bar [y]
MyLibDependencies
(provide-status [this val]
(if (odd? val)
:ok
:err))
(provide-response [this val]
(+ y val)))
(comment
(render-response (Bar. 10) 1) ;; => {:status :ok :code 11}
(render-response (Foo. 10) 1) ;; => {:status :err :code 11}
)
There are numerous examples of this style of Clojure code in the wild - in fact most of the core functions that make up Clojure itself are end up resolving to calls to protocol methods provided by the specific datastructure being used, or multimethod calls extended for the individual datatypes.
Why don't when-let and if-let support multiple bindings by default?
So:
(when-let [a ...
b ...]
(+ a b))
...instead of:
(when-let [a ...
(when-let [b ...
(+ a b)))
I am aware that I can write my own macro or use a monad (as described here: http://inclojurewetrust.blogspot.com/2010/12/when-let-maybe.html).
Because (for if-let, at least) it's not obvious what to do with the "else" cases.
At least, motivated by Better way to nest if-let in clojure I started to write a macro that did this. Given
(if-let* [a ...
b ...]
action
other)
it would generate
(if-let [a ...]
(if-let [b ...]
action
?))
and it wasn't clear to me how to continue (there are two places for "else").
You can say that there should be a single alternative for any failure, or none for when-let, but if any of the tests mutate state then things are still going to get messy.
In short, it's a little more complicated than I expected, and so I guess the current approach avoids having to make a call on what the solution should be.
Another way of saying the same thing: you're assuming if-let should nest like let. A better model might be cond, which isn't a "nested if" but more an "alternative if", and so doesn't fit well with scopes... or, yet another way of saying it: if doesn't handle this case any better.
Here is when-let*:
(defmacro when-let*
"Multiple binding version of when-let"
[bindings & body]
(if (seq bindings)
`(when-let [~(first bindings) ~(second bindings)]
(when-let* ~(vec (drop 2 bindings)) ~#body))
`(do ~#body)))
Usage:
user=> (when-let* [a 1 b 2 c 3]
(println "yeah!")
a)
;;=>yeah!
;;=>1
user=> (when-let* [a 1 b nil c 3]
(println "damn! b is nil")
a)
;;=>nil
Here is if-let*:
(defmacro if-let*
"Multiple binding version of if-let"
([bindings then]
`(if-let* ~bindings ~then nil))
([bindings then else]
(if (seq bindings)
`(if-let [~(first bindings) ~(second bindings)]
(if-let* ~(vec (drop 2 bindings)) ~then ~else)
~else)
then)))
Usage:
user=> (if-let* [a 1
b 2
c (+ a b)]
c
:some-val)
;;=> 3
user=> (if-let* [a 1 b "Damn!" c nil]
a
:some-val)
;;=> :some-val
EDIT: It turned out bindings should not be leaked in the else form.
If you use cats, then there is a mlet function that you might find useful :
(use 'cats.builtin)
(require '[cats.core :as m])
(require '[cats.monad.maybe :as maybe])
(m/mlet [x (maybe/just 42)
y nil]
(m/return (+ x y)))
;; => nil
As you can see, the mlet short-circuits when encountering a nil value.
(from section 6.5.1 nil)
Functions with closures seem to break when used with eval.
(eval {:fn (let [x "foo"] (fn [] "x"))})
;=> {:fn #<user$eval14716$fn__14717 user$eval14716$fn__14717#1ddd735>}
(eval {:fn (let [x "foo"] (fn [] x))})
;=> IllegalArgumentException No matching ctor found for class user$eval14740$fn__14741
; clojure.lang.Reflector.invokeConstructor (Reflector.java:166)
I don't really know enough about Clojure (or closure) to know if this is a bug or something which intentionally isn't allowed - can anyone shed some light on this?
Edit: Just to be clear, I'm talking specifically about the way eval handles function objects. AFAIK eval is actually designed to work with java objects, including functions; the example given on the clojure website - (eval (list + 1 2 3)) - passes a function object into eval.
Cloure's eval does not perfectly support function objects. It's not necessarily even closures that cause the problem.
For example, this did not work in Clojure 1.0.0:
(eval {:fn (fn [x] x)})
But this did:
(eval (fn [x] x))
The first example got fixed. The following also works:
(eval (let [x "foo"] (fn [] x)))
But the following still does not work:
(eval {:fn (let [x "foo"] (fn [] x))})
I can't pin it down to a single line in the compiler, but it's something about how literal objects (clojure.lang.Compiler$ObjExpr I think) get handled by eval in different contexts: e.g. at the "top" of an expression versus inside another data structure.
In general, I think, you cannot rely on being able to eval function objects in Clojure, regardless of whether or not they are closures. It happens to work for some simple examples, mostly to simplify the explanation of things like (eval (list + 1 2)). Macros should always return literal source code as data structures, not compiled functions.
Try quoting your argument to eval:
(eval '{:fn (let [x "foo"] (fn [] x))})
;=> {:fn #<user$eval345$fn__346 user$eval345$fn__346#17b6dd83>}
((:fn *1))
;=> "foo"
This is not a bug. The equivalent of (eval (list + 1 2 3)) with a "closure" is (eval (list fn [] "foo")), not (eval (fn [] "foo")).
And (eval (list fn [] "foo")) => Can't take value of a macro: #'clojure.core/fn, again indicating that you're not supposed to do things like that (and there's no need for it anyway).