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 [email protected]
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
-~----------~----~----~----~------~----~------~--~---