On Tue, Jul 26, 2011 at 5:14 PM, Ken Wesson <kwess...@gmail.com> wrote: > On Tue, Jul 26, 2011 at 6:02 AM, Petr Gladkikh <petrg...@gmail.com> wrote: >> On Tue, Jul 26, 2011 at 3:28 PM, Alan Malloy <a...@malloys.org> wrote: >>> On Jul 25, 11:10 pm, Petr Gladkikh <petrg...@gmail.com> wrote: >>>> I am trying to construct java object and assign it's fields from a map. >>>> That is given Java object of class Something { long id; String name; } >>>> and Clojure map {:id 12, :name "Impostor"} >>>> I would like to set fields of java object to respective values from map. >>>> >>>> Now, this works >>>> (let [o (Something.)] >>>> (set! (. o :id) 12) >>>> (set! (. o :name) "Impostor") >>>> o) >>>> >>>> But as soon as I use some value to get field expression compiler >>>> starts complaining "Invalid assignment target". >>>> that is >>>> (let [o (Something.) >>>> ff :id] >>>> (set! (. o ff) 12) >>>> o) >>>> I do not understand why this problem occurs. Any variations that I >>>> tried to made it work do not do the trick. >>>> Including weird (or ridiculous) ones like (set! (. o (symbol (str ":" >>>> (name ff))) 12) >>>> >>>> I suspect that this has something to do with compiler that needs field >>>> names at compile time but Clojure could use reflection for this... >>>> >>>> Can anyone point to what is wrong here? >>>> >>>> By the way is there already some function that allows to set fields of >>>> an object from a map? >>> >>> Clojure *could* use reflection to do this...unless your object had a >>> field named ff! It has to decide at compile time how to look up a >>> field, and at that time it doesn't know your object won't have a .ff >>> field, so it figures, sure, I'll set the ff field. >>> >>> If you really want to do this (hint: you don't), you can manually deal >>> with the reflection that the compiler would generate, as Shantanu >>> outlines. >> >> Could you elaborate on this? What would you use instead in this case? >> My motivation is need to construct list of Java objects and I would >> like to have some concise syntax to write them. So I decided to do >> this with maps. >> I wrote a function that acts as constructor. But long list of >> >> (set! (. obj :aa) (:aa props)) >> (set! (. obj :bb) (:bb props)) >> (set! (. obj :cc) (:cc props)) >> (set! (. obj :dd) (:dd props)) >> >> looks not very lispy. Maybe I should use macros instead? > > Untested! But should give a general idea how to do this sort of thing: > > (defmacro defsetter [class keys] > (let [o (gensym) > p (gensym)] > `(defn ~(symbol (str "set-" (.toLowercase (str class)))) > [~o ~p] > ~@(map > (fn [k] > `(set! (. ~o ~k) (~k ~p))) > keys)))) > > (defsetter Foo [:a :b]) > > (set-foo a-foo {:a 0 :b 42}) > > (defsetter Bar [:x :y :z]) > > (ser-bar a-bar {:x 4 :y 8 :z 15}) > > -- > Protege: What is this seething mass of parentheses?! > Master: Your father's Lisp REPL. This is the language of a true > hacker. Not as clumsy or random as C++; a language for a more > civilized age. >
I tried this since I have not used macroses for real problem so far. And it actually works. But I do not understand why it works. I have class: class Foo { public String s; public int v; public String toString() { return "{" + s + "," + v + "}"; } } Then in Clojure: (defsetter abcde [:s :v]) (let [afoo (actialpackage.Foo.)] (set-abcde afoo {:s "S" :v 42}) (println afoo)) But at the moment (defsetter abcde [:s :v]) is expanded nothing is known about actual class. So it is not clear to me why this works but giving field names at runtime does not. Can anyone clarify this? Maybe this wokrs because in this case compiler can infer type of java object at compile time? -- Petr Gladkikh -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en