Perhaps I'm being dense but I still fail to see what the issue is here: (defn setter [sym] `(defn ~(symbol (str "set-" sym)) [~'x ~'y] (assoc ~'x ~(keyword (str sym)) ~'y)))
(defn getter [sym] `(defn ~(symbol (str "get-" sym)) [~'x] (~(keyword (str sym)) ~'x))) (defmacro accessors [& syms] `(do ~@(map getter syms) ~@(map setter syms))) (accessors x y) (set-x {} 4) ; -> {:x 4} (get-x (set-x {} 4)) -> 4 Is this really so hard? I'll also point out that making maps work the way you propose isn't even particularly ideal because _anything_ in Clojure can be a key not just keywords. p.{"first": "Bob", "second": "Smith"} = 5 Makes absolute no sense in, say, Python, but (assoc some-map {:first "Bob" :second "Smith"} 5) is perfectly valid in Clojure. How do you propose to reconcile this? Just asking ;) On Fri, Apr 24, 2009 at 5:39 PM, Mark Engelberg <mark.engelb...@gmail.com>wrote: > > Laurent, I think we're actually mostly in agreement here, although we > differ on some of the details. > > I agree with the Principle of Uniform Access. One interpretation of > this principle is that coders should never have a public field, and > should always use getters and setters, to make the API future proof. > This is how Java does things (or has it improved in latest versions?), > but many programmers (including myself) don't like this. So most > recent languages (C#, Scala) let you start out with public fields, and > then later, you can create methods which are actually called under the > covers by the standard assignnment and lookup mechanism in the > language, disguising these dynamic properties as standard fields. The > point is, you start out using the simplest thing to express your data > structure, and then you can convert it effortlessly IF you end up > needing to. > > In Clojure, most new data structures are going to be implemented as a > map. I am well aware that you could define getters and setters for > every single field to protect yourself. But I would prefer to start > with the simplest possible implementation, and be able to grow it > gracefully if need be. In other words, I want to start out just > representing my data structure as a map. I want to be able to use the > wonderfully convenient notations that Clojure allows (e.g., > (:numerator rational) to look up the numerator in a structure > representing a rational number). And then, I want my client code to > *not break* when my needs grow. > > In Clojure, you can do amazing things with maps, making it an ideal > tool for rapid coding, especially in the initial phase where > interfaces and design needs change frequently. At the other end of > the spectrum, you can also code elaborately complex things as Java > classes, interfaces, and proxies to implement them. But there isn't > much you can do in between. If you start with a map, and your needs > grow, you're kind of stuck and need to do a pretty elaborate rewrite. > It seems to me there's a need for something that works like a map, > letting you continue to use the standard associative interface such as > get, assoc, keyword access notation, =, etc., but can handle slightly > more complex things, perhaps with better hooks for customizing > equality, or hiding certain parts of the map, or providing a special > function to be called when using assoc and get with certain keywords > on a given map. > > On Fri, Apr 24, 2009 at 9:46 AM, Laurent PETIT <laurent.pe...@gmail.com> > wrote: > > Why do you say "things kind of break down" ? > > > > (:key my-map) is a function call ? Everything is always (almost) a > > function call in clojure ? > > Yes, but as far as I know, it doesn't call anything you can customize. > I believe it calls get, which you can't hook into without > reimplementing your data structure as a proxy for the associative > interface. > > > > > I think an idea could be to have (get) and (set) polymorphic via > > multimethods (if they aren't already, maybe I don't know), but that > > would certainly be a performance killer ? > > Yes, if all the built-in things were implemented as multimethods, a > lot of my extensibility/scalability concerns would go away. But they > aren't (presumably for performance reasons). They are implemented as > Java interfaces, and you can't easily make a map respond differently > to these interfaces. You have to custom code your own map-like thing > via proxy. And equality and hashing are even more difficult to > customize. > > > > --~--~---------~--~----~------------~-------~--~----~ 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 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 -~----------~----~----~----~------~----~------~--~---