Reputation: 13
I'm trying to use java interop, to create a list of objects.
I have tried for
and doseq
, and they both have problems.
for
is lazy, and I need to create all the objects, as they interact with each other internally.
(def master-object (MasterObject.))
(for [x [1 10 50 99]]
(let [child (.createChildObject master-object)]
(.setCoefficient child x)
child))
doseq
creates all, but don't return a list.
(doseq [x [1 10 50 99]]
(let [child (.createChildObject master-object)]
(.setCoefficient child x)
child))
I was thinking about using loop
and recur
, but was wondering if could be a more idiomatic way of doing that.
Thanks
Upvotes: 1
Views: 612
Reputation: 13473
The magic word for realising lazy sequences is doall
. If you wrap it round your for
, you'll get the effect you want:
(doall
(for [x [1 10 50 99]]
(let [child (.createChildObject master-object)]
(.setCoefficient child x)
child)))
=>
(#object[interop.core.ChildObject 0x326037f1 "interop.core.ChildObject@326037f1"]
#object[interop.core.ChildObject 0x759b711 "interop.core.ChildObject@759b711"]
#object[interop.core.ChildObject 0x2bc06dcb "interop.core.ChildObject@2bc06dcb"]
#object[interop.core.ChildObject 0x4a37a35a "interop.core.ChildObject@4a37a35a"])
Notice that the returned object is a LazySeq
,not a list. And the REPL forces its realisation anyway.
If setCoefficient
returns Java this
, you can abbreviate the above to
(doall
(for [x [1 10 50 99]]
(.. master-object
(createChildObject)
(setCoefficient x))))
The structure of your code worries me. You are implementing half the association between MasterObject
and ChildObject
- a child knows its master; but not the other half - a master does not know its children. We don't see you do anything with the generated collection of children. If that is so, nothing refers to them, and they are garbage that will be disposed of whenever.
I think the MasterObject
should keep a collection of its children, added to when the ChildObject
is created in createChildObject
. Then you needn't keep the collection of created children, and doseq
is to be preferred to for
. I've done it entirely in Clojure interop as follows:
(ns interop.core)
(definterface ChildInterface
(setCoefficient [x]))
(definterface MasterInterface
(createChildObject [])
(getChildren []))
(deftype ChildObject [master ^:unsynchronized-mutable coefficient]
Object
(toString [this]
(str "Child " coefficient))
ChildInterface
(setCoefficient [this x]
(set! coefficient x)
this))
(deftype MasterObject [^:unsynchronized-mutable children]
Object
(toString [this]
(str "Master children: " (.seq children)))
MasterInterface
(createChildObject [this]
(let [child (ChildObject. this nil)]
(set! children (conj children child))
child))
(getChildren [this]
children))
(def master-object (MasterObject. []))
(doseq [x [1 10 50 99]]
(.. master-object
(createChildObject)
(setCoefficient x)))
This is still pretty ugly, as I haven't worked out how to suppress the default rendering of Java objects:
master-object
=>
#object[interop.core.MasterObject
0x3f7683a
"Master children: (#object[interop.core.ChildObject 0xb1cf4bb \"Child 1\"] #object[interop.core.ChildObject 0x16b56f70 \"Child 10\"] #object[interop.core.ChildObject 0x5dadc8ab \"Child 50\"] #object[interop.core.ChildObject 0x6f22f049 \"Child 99\"])"]
I've used a Clojure vector for the children. In this context, a Java collection would do just as well.
Upvotes: 0
Reputation: 6509
If you need to create all the objects then I think it would be idiomatic to return a vector rather than a list, for example:
(vec (for [x (range 3)]
x))
There are a few different ways to force all the output from a for
. The above is one of them. vec
is just short for into []
. So if you definitely need a realised list you could instead:
(into '() (for [x (range 3)]
x))
For creating a list of objects doseq
will not help you as it is only about 'side effects'.
Really you could look at using map
for what you want to accomplish. Make a separate mapping function and map over it:
(defn make-child [x]
(let [child (.createChildObject master-object)]
(.setCoefficient child x)
child))
(map make-child [1 10 50 99])
Upvotes: 2