Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make an ArrayList in Clojure

I need to create and populate an ArrayList in clojure and pass it to an Java API. Can someone help explain why there is a difference in the below two approaches (and why one of them doesn't work).

;;; this works
(defn make-an-array-list []
  (let [alist (java.util.ArrayList.)]
    (loop [x 0] (when (< x 6) (.add alist x) (recur (inc x)))) alist))
;;; ==> [0 1 2 3 4 5]

;;; this does not work
(defn make-an-array-list2 []
  (let [alist (java.util.ArrayList.)]
    (for [n (range 6)] (.add alist n)) alist))
;;; ==> []

Or, any suggestion in stead of the above approach?

like image 366
Alfred Xiao Avatar asked Jan 06 '14 09:01

Alfred Xiao


3 Answers

Better still, just write (ArrayList. (range 6)). Or if the java code is well written, and only requires an Iterable, List, or Collection - anything less specific than ArrayList - you can simply return (range 6).

like image 107
amalloy Avatar answered Nov 17 '22 23:11

amalloy


Use doseq instead of the lazy for. It has for-like bindings but it's meant for side-effects.

(defn make-an-array-list2 []
  (let [alist (java.util.ArrayList.)]
    (doseq [n (range 6)] (.add alist n)) alist))

;; [0 1 2 3 4 5]
like image 42
eagleflo Avatar answered Nov 17 '22 23:11

eagleflo


Here is a more explicit answer for why the second example doesn't work. The for expression is lazy; in other words, it isn't evaluated unless its result are consumed by something. You throw away the result of the for expression because you only care about the side-effects, so it's never actually evaluated.

Here is an example of the same phenomenon:

(defn example[] 
   (for [n (range 6)] 
      (println "n=" n))
   (println "done"))
(example)
;; done
;; nil
like image 24
user100464 Avatar answered Nov 17 '22 22:11

user100464