The add method that you partially apply in new-scheduler should be private, because a user can't supply the first argument it expects. You might do something like this.
(defn- add* [queue item] (...)) (defn add [scheduler item] ((scheduler :add) item)) (defn new-scheduler [] (let [queue (...)] {:add (partial add* queue)})) But again, I am not recommending this. I just wanted to point out that a closure gives you encapsulation w/o extra language features. On May 10, 2013 6:56 AM, "Colin Yates" <colin.ya...@gmail.com> wrote: > Thanks John. To be explicit - the add method shouldn't be private - it is > the only way users should add to the queue. I think this is what you meant > but you wrote "..and `add` and `clear` are your private fns..". > > Again, this paradigm shift of 'trust your users' is unfortunately alien to > me based on my experience with most of the Java devs I have come across :). > I say that not be snarky, but to highlight how much it really does change > things. The open-closed principle now becomes much simpler to realise for > example. > > Thanks again. > > > On 10 May 2013 12:44, John D. Hume <duelin.mark...@gmail.com> wrote: > >> I agree with the advice you've gotten, but since no one has mentioned it, >> I wanted to point out that you can have encapsulation w/o protocols with >> something like this. >> >> Assume a queue is your only state and `add` and `clear` are your private >> fns that take a queue as first argument. >> >> (defn new-scheduler [] >> (let [queue (...)] >> {:add (partial add queue) >> :clear (partial clear queue)})) >> >> There are several disadvantages to this, however. The biggest in my book >> is that it achieves your goal, and you're limited in the same way your >> users are. You can't add behavior to an already created scheduler (unless >> it's built on adding and clearing). Furthermore, if you dynamically >> recompile `add` or `clear`, it won't change the behavior of an already >> created scheduler, since partial has the fns, not the symbols or vars that >> point at them. (These same disadvantages apply to a reified protocol.) >> >> As others have recommended, just return a map. Keep in mind that the >> documentation is just a `(doc new-scheduler)` away and that auto-completion >> will tend to send people back into your ns's fns rather than into the >> internals of a data structure. >> On May 10, 2013 5:51 AM, "Colin Yates" <colin.ya...@gmail.com> wrote: >> >>> Thanks Korny. >>> >>> Ok, the over-ridding theme seems to be: expose state, even if it is >>> dangerous, but expect consumers to 'do the right thing' and read the >>> documentation. >>> >>> I can see that. I guess I have worked (and to be honest, been guilty >>> myself) with too many people who don't read the documentation, use >>> auto-complete to find something that looks like it might work and then move >>> on to the next chunk of wiring things up in XML :). >>> >>> I think I also got hung up on the 'data as a contract'. The point here >>> is that I am not returning data, rather I am defining a service. A subtle >>> difference but an important one I think. >>> >>> Keep the comments coming! >>> >>> >>> On 10 May 2013 11:37, Korny Sietsma <ko...@sietsma.com> wrote: >>> >>>> I would generally handle this sort of encapsulation at the namespace >>>> level. >>>> >>>> Put (create-woobly) and (add-job) and all the other woobly-related >>>> functions into a woobly namespace. Also add any functions that access info >>>> from a woobly bag-o-state, or mutate a woobly to make a woobly-with-extras. >>>> >>>> Functions that might dangerously expose internals of a woobly can be >>>> made private, or possibly you can just document them in a way to warn folks >>>> away from "bad" behaviour. >>>> >>>> While external users of (woobly/create-woobly) can in theory dig into >>>> the internals of the woobly "object", but it should be relatively obvious >>>> that this isn't a good idea. >>>> >>>> I'd defer making protocols until you actually need polymorphism. >>>> >>>> - Korny >>>> >>>> >>>> >>>> On 10 May 2013 03:03, Colin Yates <colin.ya...@gmail.com> wrote: >>>> >>>>> Thanks for all the helpful responses. >>>>> >>>>> One reason I want to hide the internals is that I don't want people to >>>>> add jobs directly to the queue. (add-job) will put a map containing the >>>>> provided function onto the queue. Not really relevant, but this is so >>>>> that >>>>> I can track queue timings that I can later on use to determine how much >>>>> capacity the system can handle. >>>>> >>>>> I am nervous as well about "expose internals but trust people to do >>>>> the right thing" because in this case, if I was a consumer and saw that >>>>> queue, particularly given the emphasis about data being the contract etc. >>>>> then why would I think *not* to use it. >>>>> >>>>> I do appreciate the point about not needlessly obfuscating information >>>>> - this is a slightly different case. >>>>> >>>>> Sounds like in this case, either reify is the way to go or maybe >>>>> return a bad of data but have this stuff in an 'internal' map (i.e. >>>>> {:internal {:queue...}}) >>>>> >>>>> Thanks a bunch - really helpful. >>>>> >>>>> >>>>> On 9 May 2013 17:30, James Reeves <ja...@booleanknot.com> wrote: >>>>> >>>>>> On 9 May 2013 17:07, Colin Yates <colin.ya...@gmail.com> wrote: >>>>>> >>>>>>> The part I am struggling with is how to create a Woobly without >>>>>>> exposing its internals. >>>>>>> >>>>>> >>>>>> To what end? What's the benefit? >>>>>> >>>>>> If you take a look at some internal data structures Clojure uses, >>>>>> like zippers or protocols, you'll notice that they're just maps. In >>>>>> general >>>>>> there's no need to try and obfuscate data to stop people from diving into >>>>>> the internals; just don't provide a public API for the internal parts and >>>>>> people will get the hint. >>>>>> >>>>>> - James >>>>>> >>>>>> -- >>>>>> -- >>>>>> 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 >>>>>> Note that posts from new members are moderated - please be patient >>>>>> with your first post. >>>>>> 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 >>>>>> --- >>>>>> You received this message because you are subscribed to a topic in >>>>>> the Google Groups "Clojure" group. >>>>>> To unsubscribe from this topic, visit >>>>>> https://groups.google.com/d/topic/clojure/D2OBBPTxGfY/unsubscribe?hl=en >>>>>> . >>>>>> To unsubscribe from this group and all its topics, send an email to >>>>>> clojure+unsubscr...@googlegroups.com. >>>>>> >>>>>> For more options, visit https://groups.google.com/groups/opt_out. >>>>>> >>>>>> >>>>>> >>>>> >>>>> -- >>>>> -- >>>>> 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 >>>>> Note that posts from new members are moderated - please be patient >>>>> with your first post. >>>>> 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 >>>>> --- >>>>> You received this message because you are subscribed to the Google >>>>> Groups "Clojure" group. >>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>> an email to clojure+unsubscr...@googlegroups.com. >>>>> >>>>> For more options, visit https://groups.google.com/groups/opt_out. >>>>> >>>>> >>>>> >>>> >>>> >>>> >>>> -- >>>> Kornelis Sietsma korny at my surname dot com http://korny.info >>>> .fnord { display: none !important; } >>>> >>>> -- >>>> -- >>>> 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 >>>> Note that posts from new members are moderated - please be patient with >>>> your first post. >>>> 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 >>>> --- >>>> You received this message because you are subscribed to a topic in the >>>> Google Groups "Clojure" group. >>>> To unsubscribe from this topic, visit >>>> https://groups.google.com/d/topic/clojure/D2OBBPTxGfY/unsubscribe?hl=en >>>> . >>>> To unsubscribe from this group and all its topics, send an email to >>>> clojure+unsubscr...@googlegroups.com. >>>> For more options, visit https://groups.google.com/groups/opt_out. >>>> >>>> >>>> >>> >>> -- >>> -- >>> 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 >>> Note that posts from new members are moderated - please be patient with >>> your first post. >>> 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 >>> --- >>> You received this message because you are subscribed to the Google >>> Groups "Clojure" group. >>> To unsubscribe from this group and stop receiving emails from it, send >>> an email to clojure+unsubscr...@googlegroups.com. >>> For more options, visit https://groups.google.com/groups/opt_out. >>> >>> >>> >> -- >> -- >> 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 >> Note that posts from new members are moderated - please be patient with >> your first post. >> 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 >> --- >> You received this message because you are subscribed to a topic in the >> Google Groups "Clojure" group. >> To unsubscribe from this topic, visit >> https://groups.google.com/d/topic/clojure/D2OBBPTxGfY/unsubscribe?hl=en. >> To unsubscribe from this group and all its topics, send an email to >> clojure+unsubscr...@googlegroups.com. >> For more options, visit https://groups.google.com/groups/opt_out. >> >> >> > > -- > -- > 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 > Note that posts from new members are moderated - please be patient with > your first post. > 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 > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/groups/opt_out. > > > -- -- 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 Note that posts from new members are moderated - please be patient with your first post. 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.