On Aug 18, 3:15 pm, Chouser <[EMAIL PROTECTED]> wrote:
> Let's say I have a library of functions that operate on a some data,
> and I really *really* don't want client code to be able to see the
> data directly.  But I still want "normal" API patterns for access via
> functions.  For example, a guessing game:
>
> (clojure/in-ns 'guesslib)
> (clojure/refer 'clojure)
>
> (def #^{:private true} thekey (gensym))
>
> (defn new-target [mx]
>   (let [t (Math/floor (* mx (Math/random)))]
>     (fn [k] (when (= k thekey) t))))
>
> (defn guess [tf g]
>   (let [t (tf thekey)]
>     (cond (< g t) :too-low
>           (> g t) :too-high
>           :else   :you-win)))
>
> Now in the user namespace, you could have this interaction:
>
> user=> (refer 'guesslib)
> nil
> user=> (def tf (new-target 10))
> #'user/tf
> user=> tf
> [EMAIL PROTECTED]
> user=> (tf guesslib/thekey)
> java.lang.IllegalStateException: var: guesslib/thekey is not public
>
> I've got a guess target, but I can't see it directly.  However, I can
> still interact with it:
>
> user=> (guess tf 5)
> :too-high
> user=> (guess tf 2)
> :too-low
> user=> (guess tf 4)
> :you-win
>
> Nice, right?  Except there's private and then there's private:
>
> user=> (def stolen (ref nil))
> #'user/stolen
> user=> (clojure/in-ns 'guesslib)  ; now you see where I'm going
> #<Namespace: guesslib>
> guess=> (dosync (ref-set user/stolen thekey))
> G__2133
> guess=> (in-ns 'user)
> #<Namespace: user>
> user=> (guess tf (tf @stolen))
> :you-win
>
> I win every time. :-/  So, my question is -- what's the right way to
> do this?  Or is my goal itself the problem?
>
> Another way to go about it is to put all the functions that need
> access to the target value in its scope (currently this is just
> "guess", but this is just an example of a larger problem).  In order
> to preserve a normal calling API, I'd have to do something like:
>
> (clojure/in-ns 'guesslib)
> (clojure/refer 'clojure)
>
> (defn new-target [mx]
>   (let [t (Math/floor (* mx (Math/random)))]
>     {'guess (fn [g]
>                 (cond (< g t) :too-low
>                       (> g t) :too-high
>                       :else   :you-win))}))
>
> (defn guess [fmap & args]
>   (apply ('guess fmap) args))
>
> ...so the toplevel functions just delegate to the closures in the map.
>  I suppose one could make a macro to reduce the repetitiveness of
> these top-level functions, but it still seems rather awkward.
>
> What am I missing?

Not much. Clojure's namespaces are to protect against accident, not
malice. And closures, as you showed, provide for truly inaccessible
data.

Rich
--~--~---------~--~----~------------~-------~--~----~
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 [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to