I am a little confused by the clojure instance? function. It seems quite happy to take a single argument. So
(instance? String)
works fine, but always returns false.
Am I missing something here? I've done this twice in two days, and both times it took me a quite a long time to debug (yes, I agree, to make the mistake once might be regarded as misfortune, but twice looks like carelessness).
Why doesn't it break, with an arity error?
Note added later:
As of Clojure 1.6 this has been fixed!
http://dev.clojure.org/jira/browse/CLJ-1171
Interesting... even though instance? is defined in core.clj, it appears that there is special handling built in to clojure.lang.Compiler for (instance?) forms.
Compiler.java, line 3498:
if(fexpr instanceof VarExpr && ((VarExpr)fexpr).var.equals(INSTANCE))
{
if(RT.second(form) instanceof Symbol)
{
Class c = HostExpr.maybeClass(RT.second(form),false);
if(c != null)
return new InstanceOfExpr(c, analyze(context, RT.third(form)));
}
}
I interpret that to mean that, when you compile/evaluate an (instance?) form, the function defined in core.clj is ignored in favor of the hard-wired behavior, which does interpret a missing second argument as nil. I'm guessing this is done for performance reasons, as a sort of in-lining.
Apparently this special handling only applies in certain cases (and I'm not familiar enough with the compiler to know what they are). As illustrated by Ankur's answer, there are ways of calling instance? that cause the function defined in core.clj to be invoked.
I think it is a bug. If you define a new version of instance?, e.g.
(def
^{:arglists '([^Class c x])
:doc "Evaluates x and tests if it is an instance of the class
c. Returns true or false"
:added "1.0"}
foo? (fn foo? [^Class c x] (. c (isInstance x))))
you will get the expected exception
user=> (foo? String "bar")
true
user=> (foo? String 1)
false
user=> (foo? String)
ArityException Wrong number of args (1) passed to: user$foo-QMARK- clojure.lang.AFn.throwArity (AFn.java:437)
If you look at the instance? code you will see that the method isInstance of Class is called:
(def
^{:arglists '([^Class c x])
:doc "Evaluates x and tests if it is an instance of the class
c. Returns true or false"
:added "1.0"}
instance? (fn instance? [^Class c x] (. c (isInstance x))))
Looks like under the hood, nil (or false) is considered as the default value for x parameter when passed to the isInstance and that returns false.
Hmm....interesting... all the below calls fails (which is how it is supposed to be):
user=> (.invoke instance? String)
ArityException Wrong number of args (1) passed to: core$instance-QMARK- clojure.lang.AFn.throwArity (AFn.java:437)
user=> (instance? (type ""))
ArityException Wrong number of args (1) passed to: core$instance-QMARK- clojure.lang.AFn.throwArity (AFn.java:437)
user=> (apply instance? String [])
ArityException Wrong number of args (1) passed to: core$instance-QMARK- clojure.lang.AFn.throwArity (AFn.java:437)
user=> (#'instance? Long)
ArityException Wrong number of args (1) passed to: core$instance-QMARK- clojure.lang.AFn.throwArity (AFn.java:437)
Event creating a new instance of "instance?" function object works as it is supposed to work:
user=> (def a (.newInstance (aget (.getConstructors (type instance?)) 0) (into-array [])))
#'user/a
user=> (a String)
ArityException Wrong number of args (1) passed to: core$instance-QMARK- clojure.lang.AFn.throwArity (AFn.java:437)
user=> (a String "")
true
Related
I am pretty new with Clojure language.
While reading about Clojure functions, I find the example #([%]). So I try to use it as follows:
(def test1 #([%]))
(test1 5)
As a result, I get the following error:
ArityException Wrong number of args (0) passed to: PersistentVector clojure.lang.AFn.throwArity (AFn.java:429)
which seems to be that it is trying to invoke the array I wanted to return.
After digging a while, I find a solution as follows:
(def test1 #(-> [%]))
(test1 5)
I would have some questions:
Why doesn't the #([%]) work? What did I do with the expression #([x])?
In the correct example I am using the thread-first macro. Based on its documentation, it is used to pass an argument to the next function, e.g. (-> x (+ 1)). In this case I do not even have a function to pass to; *what is the next function in this context? I can not realize why it solved my issue
Question 1
The syntax #([%]) translates into: "Create a function that when called will evaluate the expression ([%]) with % being the first (and only) argument passed to the function". This expression has the syntax of a function call with [%] being the function to be called. You can see what goes on using a macroexpand:
(macroexpand '#([%]))
;; => (fn* [p1__6926#] ([p1__6926#]))
The class of persistent vectors in clojure is clojure.lang.PersistentVector. They implement the IFn interface for arity 1, so that you can treat the vector as a function mapping an index to an element. But they do not implement arity 0, which is what you are trying to call. In other words, your code does not work:
(def test1 #([%]))
(test1 5) ;; ERROR
However, if you would pass the argument 0 to your function [%], you would get back the element:
(def test1 #([%] 0))
(test1 5)
;; => 5
Do you see what happens? However, for the thing you are trying to do, there is a better way: The [a b c] syntax is just sugar for calling (vector a b c). So to get something that works, you can just do
(def test1 vector)
(test1 5)
;; => [5]
Question 2
The thread-first macros has the syntax of (-> x f0 f1 f2 ...) where x is the initial value and f0, f1 and so on are function calls with their first argument left out to be replaced by the value that is being piped through. Again we can use macroexpand to understand:
(macroexpand '(-> x f0 f1 f2))
;; => (f2 (f1 (f0 x)))
But in your case, the function calls are left out. To analyze your second example, we need to use clojure.walk/macroexpand-all for a full expansion, because we have nested macros:
(clojure.walk/macroexpand-all '#(-> [%]))
;; => (fn* [p1__6995#] [p1__6995#])
although, we can also look at it one step at a time:
(macroexpand '#(-> [%]))
;; => (fn* [p1__7000#] (-> [p1__7000#]))
(macroexpand '(-> [p1__7000#]))
;; => [p1__7000#]
So to answer your question: There is no next function in (-> [%]). The number of next functions can be any non-negative number, including zero, which is the case with (-> [%]).
#Rulle gives an exhaustive explanation of the details.
May I point out the most important part? Your reference from Clojure.org says:
;; DO NOT DO THIS
#([%])
So, don't do that! It is a silly trick that will only cause confusion & pain. Why would you want that???
I get the following weird behaviour from a clojure function: When I call it with one argument it seems as if it is a function, when I call it without arguments it appears to be a symbol. Any ideas how this can be?
this is what happens in the interpreter:
=> (input-updatef -1)
ArityException Wrong number of args (1) passed to: modelingutils/create-process-level/input-updatef--2954 clojure.lang.AFn.throwArity (AFn.java:429)
and when I try calling it without any argument:
=> (input-updatef)
ArityException Wrong number of args (0) passed to: Symbol clojure.lang.AFn.throwArity (AFn.java:429)
Thx!
Answering "how this can be":
user=> (defn foo [] ('foo))
#'user/foo
user=> (foo 1)
ArityException Wrong number of args (1) passed to: user/foo clojure.lang.AFn.throwArity (AFn.java:429)
user=> (foo)
ArityException Wrong number of args (0) passed to: Symbol clojure.lang.AFn.throwArity (AFn.java:429)
Of course your input-updatef situation may be more subtle, but it is at least clear that
either the actual input-updatef function has no unary overload or it has one, but when you call it it ends up calling a function that has no unary overload with just one argument;
it has a nullary overload;
calling the nullary overload results in a call to a symbol with no arguments.
Also, based on the modelingutils/create-process-level/input-updatef--2954 part of your error message it seems to me that input-updatef might be a "local function" – created using letfn or introduced as the value of a let binding – returned at some point from a function called create-process-level. Here's an example of what that could look like:
user=> (defn foo
([]
('foo))
([x]
(letfn [(f [])]
(f x))))
#'user/foo
user=> (foo 1)
ArityException Wrong number of args (1) passed to: user/foo/f--4 clojure.lang.AFn.throwArity (AFn.java:429)
user=> (foo)
ArityException Wrong number of args (0) passed to: Symbol clojure.lang.AFn.throwArity (AFn.java:429)
Using
(defn foo
([]
('foo))
([x]
(let [f (fn [])]
(f x))))
would have the same effect.
Thanks, both answers helped.
I did not post the definition, because it contained a complex macro..
The problem was that I called the macro from a normal function and supplied an argument (an ff function) to this macro from the argument list of the calling function. This ff was interpreted as a symbol at macro evaluation time -- this is what caused the strange behaviour.
Solution: I changed the outer calling function into a macro, and unquoted ff in the argument list of the called macro.
For example, as in the example here,
=> (-> "a b c " .toUpperCase (.replace "A" "X") (.split " ") first)
=> "X"
I'd like to be able to do something like
=> (-> ^String "a b c " .... etc etc
to avoid the reflection penalties, esp. in interfacing with java code.
It is possible to type hint expressions using the -> macro. While the following uses reflection:
(set! *warn-on-reflection* true)
(def s "1")
(-> s .toString)
;; Reflection warning, NO_SOURCE_PATH:1:1 - reference to field toString can't be resolved.
;;= "1"
This doesn't:
(-> ^String s .toString)
;;= "1"
Maybe if you share a specific expression where you are finding it hard or impossible to type hint we can help you better.
There is a known situation where the type hint attached to the macro's &form expression is discarded, see this JIRA ticket Macroexpansion discards &form metadata. Maybe this is what you are seeing?
Yes, it is possible.
If you need to type-hint the initial argument to ->, you can do it directly, either inside or outside the -> form:
(-> ^String (foo) .toUpperCase)
(let [^String f (foo)]
(-> f .toUpperCase))
There will be no reflection in either case.
If the value that you wish to type-hint arises at an intermediate step in the -> chain, then you can type-hint it by putting the type hint on the -> step:
;; note the type hints on identity and (identity)
(-> ^String (foo) .toUpperCase ^String identity .toLowerCase)
(-> ^String (foo) .toUpperCase ^String (identity). toLowerCase)
Again, there will be no reflection in either case.
(Tested at a 1.7.0-alpha5 REPL.)
Well, in your case at least, there are no reflection penalties.
user=> (set! *warn-on-reflection* true)
true
user=> (-> "a b c " .toUpperCase (.replace "A" "X") (.split " ") first)
"X"
If you want to be even more sure:
user=> (def i 23)
#'user/i
user=> (.toString i)
Reflection warning, NO_SOURCE_PATH:1:1 - reference to field toString can't be resolved.
"23"
I have a function like this:
(defn foo [{a :keya b :keyb}]
(list a b))
And i'm calling it like this:
(foo {:keya "hi"}) ; Returns ("hi" nil)
If I don't give keyb keyword argument, it takes nil for that. Is there a way to ensure that it throws exception for it instead of taking it as nil.
( I know that I can manually check and throw an exception, but is there any special option which enforces the constraints.)
You can use a precondition (http://clojure.org/special_forms#toc9) to assert the key is present:
(defn foo [{a :keya b :keyb}]
{:pre [(not (nil? b))]}
(list a b))
This will throw an AssertionError when the key is nil.
No, but of course because Clojure is a lisp you can define your own macro that handles the boring "manual checking" for you automatically.
aldazosa gave you the right solution, but {:keya nil :keyb nil} is the valid map too. To allow nil values you may use contains? instead of nil? check:
(defn foo [{a :keya b :keyb :as m}]
{:pre [(every? (partial contains? m)
[:keya :keyb])]}
(list a b))
If you want something more complex look at Validateur or bouncer
Given a list of names for variables, I want to set those variables to an expression.
I tried this:
(doall (for [x ["a" "b" "c"]] (def (symbol x) 666)))
...but this yields the error
java.lang.Exception: First argument to def must be a Symbol
Can anyone show me the right way to accomplish this, please?
Clojure's "intern" function is for this purpose:
(doseq [x ["a" "b" "c"]]
(intern *ns* (symbol x) 666))
(doall (for [x ["a" "b" "c"]] (eval `(def ~(symbol x) 666))))
In response to your comment:
There are no macros involved here. eval is a function that takes a list and returns the result of executing that list as code. ` and ~ are shortcuts to create a partially-quoted list.
` means the contents of the following lists shall be quoted unless preceded by a ~
~ the following list is a function call that shall be executed, not quoted.
So ``(def ~(symbol x) 666)is the list containing the symboldef, followed by the result of executingsymbol xfollowed by the number of the beast. I could as well have written(eval (list 'def (symbol x) 666))` to achieve the same effect.
Updated to take Stuart Sierra's comment (mentioning clojure.core/intern) into account.
Using eval here is fine, but it may be interesting to know that it is not necessary, regardless of whether the Vars are known to exist already. In fact, if they are known to exist, then I think the alter-var-root solution below is cleaner; if they might not exist, then I wouldn't insist on my alternative proposition being much cleaner, but it seems to make for the shortest code (if we disregard the overhead of three lines for a function definition), so I'll just post it for your consideration.
If the Var is known to exist:
(alter-var-root (resolve (symbol "foo")) (constantly new-value))
So you could do
(dorun
(map #(-> %1 symbol resolve (alter-var-root %2))
["x" "y" "z"]
[value-for-x value-for-y value-for z]))
(If the same value was to be used for all Vars, you could use (repeat value) for the final argument to map or just put it in the anonymous function.)
If the Vars might need to be created, then you can actually write a function to do this (once again, I wouldn't necessarily claim this to be cleaner than eval, but anyway -- just for the interest of it):
(defn create-var
;; I used clojure.lang.Var/intern in the original answer,
;; but as Stuart Sierra has pointed out in a comment,
;; a Clojure built-in is available to accomplish the same
;; thing
([sym] (intern *ns* sym))
([sym val] (intern *ns* sym val)))
Note that if a Var turns out to have already been interned with the given name in the given namespace, then this changes nothing in the single argument case or just resets the Var to the given new value in the two argument case. With this, you can solve the original problem like so:
(dorun (map #(create-var (symbol %) 666) ["x" "y" "z"]))
Some additional examples:
user> (create-var 'bar (fn [_] :bar))
#'user/bar
user> (bar :foo)
:bar
user> (create-var 'baz)
#'user/baz
user> baz
; Evaluation aborted. ; java.lang.IllegalStateException:
; Var user/baz is unbound.
; It does exist, though!
;; if you really wanted to do things like this, you'd
;; actually use the clojure.contrib.with-ns/with-ns macro
user> (binding [*ns* (the-ns 'quux)]
(create-var 'foobar 5))
#'quux/foobar
user> quux/foobar
5
Evaluation rules for normal function calls are to evaluate all the items of the list, and call the first item in the list as a function with the rest of the items in the list as parameters.
But you can't make any assumptions about the evaluation rules for special forms or macros. A special form or the code produced by a macro call could evaluate all the arguments, or never evaluate them, or evaluate them multiple times, or evaluate some arguments and not others. def is a special form, and it doesn't evaluate its first argument. If it did, it couldn't work. Evaluating the foo in (def foo 123) would result in a "no such var 'foo'" error most of the time (if foo was already defined, you probably wouldn't be defining it yourself).
I'm not sure what you're using this for, but it doesn't seem very idiomatic. Using def anywhere but at the toplevel of your program usually means you're doing something wrong.
(Note: doall + for = doseq.)