Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why argument list as ArraySeq?

Consider the following function:

user> (defn first-args [& args]
            (args 0))
#'user/first-args
user> (first-args 1 2 3) ;=> clojure.lang.ArraySeq cannot be cast to clojure.lang.IFn

Why is the argument list a clojure.lang.ArraySeq and not something much more common like a PersistentVector? Or why doesn't ArraySeq implement IFn? Performance reasons? Seems like you have to know the underlying implementation of things a bit while doing Clojure. Feel free to enlighten me.

PS: this question is not about "is this idiomatic or not?" Just asking why this is like it is.

like image 844
Michiel Borkent Avatar asked Nov 20 '11 22:11

Michiel Borkent


2 Answers

(defn first-args [& args]
  (first args))

(apply first-args (range)) 
;=> 0

You can apply a function to an infinite argument sequence, consuming items only as needed. If & args were required to be a vector (or anything more concrete than an ISeq), this would be impossible.

As for why seqs aren't callable: it would encourage using them in a way that performs very poorly.

like image 91
amalloy Avatar answered Nov 08 '22 09:11

amalloy


Other answers are already good, but just wanted to present an alternative to achieve the same effect:

(defn first-args [first-arg & others] 
  first-arg)

(first-args 1 2 3)
=> 1

i.e. you can explicitly name the first argument in the function definition.

like image 5
mikera Avatar answered Nov 08 '22 08:11

mikera