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