Mapping mutable methods onto Java objects in Clojure -


using clojure, suppose t represents java object, , have collection of [ts].

how can map .setter [ts]? i'm having trouble using (map #(.setter %1 %2) ts [vals]). when access associated getters afterwards, return list of nils.

as example of arraylist java class. create 3 of those, , add "s1" first one, "s2" second , "s3" third. "setter".

then read first value of each, , expect "s1", "s2", "s3" - that's getter in example.

(let [ts [(java.util.arraylist. 1)           (java.util.arraylist. 1)           (java.util.arraylist. 1)]]   ; add 1 element each of arraylist's   (doall (map #(.add %1 %2) ts ["s1" "s2" "s3"]))    ; verify elements indeed added.   (doall (map #(.get %1 0) ts))) 

this example works expected - latter mapv returns ("s1" "s2" "s3").

why similar approach not work you? well, strong suspiction that's because use map returns lazy sequence.

map returns lazy sequence, means not evaluate unless try get/use values produced - , don't need return value setter. means setter never called.

that's why i've used doall - take lazy sequence , realize it, meaning each element computed (in case - each setter called).

my example, when use map , not doall when setting elements, fail:

(let [ts [(java.util.arraylist. 1)           (java.util.arraylist. 1)           (java.util.arraylist. 1)]]   ; use lazy map here - without doall   (map #(.add %1 %2) ts ["s1" "s2" "s3"])   (doall (map #(.get %1 0) ts)))  ; java.lang.indexoutofboundsexception: index: 0, size: 0 

it fails indeed, because no element got added.

alternatively, can use mapv variant returns vector , hence not lazy:

(let [ts [(java.util.arraylist. 1)           (java.util.arraylist. 1)           (java.util.arraylist. 1)]]   ; use lazy map, realize sequence using doall   (doall (map #(.add %1 %2) ts ["s1" "s2" "s3"]))   (mapv #(.get %1 0) ts)) 

as pointed out @john wiseman in comment, though, mapv worse choice because it's not clear it's used force realization, while doall makes clear , obvious.


a word lazy sequences:

a lazy seq seq members aren't computed until try access them. 

(source)

it's thing learn more lazy seqs, they're powerful tool used on in clojure codebases. 1 counter-intuitive thing bring table ability create infinite sequences, i.e. (range) creates infinite sequence of numbers starting 0. it's legal do:

(map #(* % %) (range)) 

it create infinite lazy sequence of squares of numbers!


Comments