On Mar 22, 2009, at 10:27 PM, Mark Engelberg wrote:
> > I've been thinking quite a bit about the OO side of Clojure the past > couple of days, and trying to figure out how common OO design patterns > would look when ported over to Clojure's way of doing things. > > The most obvious thing that others have noted is that you can > effectively simulate a mutable object by having a ref that holds a > hash map. You can then write getters and setters, and other kinds of > supporting functions that use and manipulate the ref, and the hash map > contained therein. But as far as I can tell, there's no way to stop a > client from simply dereferencing the ref and extracting or > manipulating the "private" information in the hash map and shoving it > back into the ref. Even if you trust a client to do the right thing, > if the object is complex, it might be hard for other programmers to > figure out which properties are meant to be manipulated, and which are > "off-limits". > > I suspect that if you use double-colon keywords for the keys, you get > a bit more privacy in the sense that these keys are slightly harder to > accidentally manipulate from other namespaces, so perhaps that could > at least be an informal convention for "this is private". Or perhaps > it's better to keep as much "private" data in the metadata as possible > (although I would think that in many cases, the private data would > still be essential to the notion of equality). Any other tricks or > techniques for helping to hide or separate out the portions of a data > structure that are meant to be accessed or "altered" from the portions > that should only be accessed and changed by the existing support > functions? > One simple (simplistic?) way to guarantee privacy is through closures: (defn make-person [first-name last-name age sex] (let [age (ref age)] {:first-name (fn [] first-name) :last-name (fn [] last-name) :sex (fn [] sex) :age (fn [] @age) :set-age (fn [new-age] (dosync (ref-set age new-age)))})) person=> (def me (make-person "David" "Sletten" 39 "male")) #'person/me person=> ((me :first-name)) "David" person=> ((me :last-name)) "Sletten" person=> ((me :age)) 39 person=> ((me :set-age) 40) 40 person=> ((me :age)) 40 There's no way to manipulate the age ref except through the :set-age function. This may not scale though if every 'object' carries around its own set of all the methods. Aloha, David Sletten --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---