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
-~----------~----~----~----~------~----~------~--~---

Reply via email to