If I understood your original article, you were saying something that amounted to these 3 assertions:
1.) to future-proof our code against changes, and to avoid being verbose, we need polymorphism. 2.) we need some way to establish constraints (contracts) on that polymorphism, or else it will become difficult to understand, and it might be extended in dangerous and unintended ways. 3.) the Abstract Container gives us an excellent way to both achieve the polymorphism we are after, while also making clear what the limits on this polymorphism should be. The Abstract Container indicates to future developers how we expect them to extend this code. I agree with #1 and #2 but I have my doubts about #3. While that Pattern can clearly work (it's been implemented a million times, so clearly it can be made to work) it strikes me as being more verbose than necessary. I would ask if there is a less verbose way of achieving the goals of #1 and #2? Also, I was intrigued by this: > In the case of iroh... if I had used strictly multimethods, I would have > been very confused. If I had used strictly protocols... well I couldn't for > a number of reasons.. but if I did, I would have been even more > confused because of the number of subconditions that I had to implement. This made me curious about iroh, so I went and looked here: https://github.com/zcaudate/iroh/blob/master/src/iroh/element/multi.clj and I notice this: (defn multi-element [m v] (element {:tag :multi :name (get-name v) :array v :lookup m :cache (atom {})})) (defmethod to-element clojure.lang.APersistentMap [m] (let [v ( to-element-array m)] (multi-element m v))) (defmethod to-element clojure.lang.APersistentVector [v] (let [m (reduce (fn [m ele] (assoc-in m (to-element-map-path ele) ele)) {} v)] (multi-element m v))) It strikes me that you could acheive a high level of polymorphism (satisfying #1) if multi-element was a function that was passed in as an argument to to-element. That would be flexible, although, to satisfy #2, you would want to establish some kind of contract to set some limits on that flexibility. There are 3 ways that I might do this: a.) I might use run-time checks, such as pre-conditions, on the arguments given to multi-element. b.) I might use something like Typed Clojure to have compile time warnings regarding the arguments given to multi-element. c.) I might hard-code multi-element, as you have done, but the map that you've hard-coded could become a Record that I pass into multi-element as an argument, thus making multi-element more polymorphic. These approaches let me achieve #1 and #2 without the complexity of the Abstract Container Pattern. Have I missed something? If the Abstract Container Pattern was really the the best strategy for iroh, can you make clear why that is? On Tuesday, July 28, 2015 at 5:09:22 AM UTC-4, zcaudate wrote: > > Hey guys, > > Thanks for the feedback and your very insightful comments. > > Yep... this is OO alright =) > > I realised only after I wrote the article that I was implementing a > Lifecycle clone with IRunnable example. However, the concept I am > mentioning is much more general than components in terms of its scope: > > A similar `abstract class` for a reflective functional dispatch mechanism > is defined here: > https://github.com/zcaudate/iroh/blob/master/src/iroh/types/element.clj > > and extended by the `concrete classes' here: > https://github.com/zcaudate/iroh/tree/master/src/iroh/element > > In the case of iroh... if I had used strictly multimethods, I would have > been very confused. If I had used strictly protocols... well I couldn't for > a number of reasons.. but if I did, I would have been even more confused > because of the number of subconditions that I had to implement. iroh was > the first library that I had built that used this pattern and it was so > successful that I've been repeating the process over and over again since. > > What I wanted to achieve was to have the equivalent of an `abstract class` > - the concept of code with abstract functionality that provides a framework > for the heavy lifting to be done. `Concrete classes` can just extend > aforementioned `abstract class` with minimal code and get all of the > benefits. > > I've used this pattern with great success in many, many times and it > provides a counter balance to the functional paradigm in terms of packaging > up functionality. Clojure doesn't force us into one paradigm or the other > and sometimes it is just more stylish to use the OO paradigm. The whole > point of OO, multimethods and protocols is to do polymorphic dispatch, > which is just a way to break a large cond statement into pieces that can > then also be further extended. > > Please also note that not all OO frameworks are equal. Java uses a class > inheritence approach whereas javascript uses a prototype model. The > `abstract container` pattern that I was describing is probably closer to > the JS model but to be honest, I don't really know what it is. Ultimately, > it adds a middle tier of functionality in systems that have a plugin type > mechanism. I'm sure there are equivalent functional contructs... but that > was not the point of the pattern. This pattern has been very useful for me; > clojure's protocols and multimethods were not enough to do what I needed to > do - but combination of the two works wonders =) > > Since the article, the pattern has been codified here: > > https://github.com/zcaudate/hara/blob/master/src/hara/extend/abstract.clj#L196 > > Hope that helps in clarifying the motivation behind the article and the > pattern > > > Chris > > > > > > > > On Monday, July 27, 2015 at 11:42:21 PM UTC+5:30, Colin Yates wrote: >> >> I think his last sentence gives you the answer: >> >> "A warm shoutout to Tushar, Lyndon, Dean, Alan, Hank, Derek, and all the >> guys at clj-melb that gave feedback and helped flesh out this rehash of *OO >> design*.” (my emphasis) >> >> He wanted an OO approach and has implemented one; specifically behaviour >> and state coupled together. I think neither Typed Clojure nor Contracts >> would have achieved this guy’s goal as they are about enforcing a contract >> (either the shape of data or effects of a fn) in the ‘functional’ paradigm; >> this guy clearly wanted something in the OO paradigm. >> >> Is there a ‘functional’ implementation which gives the same benefits; >> sure, but that isn’t what he wanted. Are there a bunch of ‘upgrades’ that I >> am sure we could all apply; sure, but again it seems like he was setting >> out with a very specific goal in mind and has achieved that. >> >> On 27 Jul 2015, at 18:37, Lawrence Krubner <lawr...@rollioforce.com> >> wrote: >> >> I have a question about this: >> >> "Servers that are running on a particular port can be tracked and >> stopped. I have to say, this was the feature that I wanted the most, which >> motivated the framework's design. The annoying thing about development in >> emacs is that I have to be careful of not losing the reference to the >> server. Since there was no way of stopping it unless the repl is restarted. >> I wanted to implement a registery for references to running servers to be >> saved." >> >> http://z.caudate.me/the-abstract-container-pattern/ >> >> I have the impression that he's going over the same territory as that >> covered by Stuart Sierra, though Zheng doesn't mention "Component" nor >> "Sierra". But he offers this as an example of what he's after: >> >> (defprotocol IRunnable (start! [system]) (stop! [system]) (restart! >> [system]) (started? [system]) (stopped? [system])) >> >> That much seems similar to Sierra's system. Zheng seems to add an >> additional layer by simulating an abstract class above his protocols. As he >> says: >> >> >> - A single deftype acts as the *abstract container*, extending one or >> more protocols >> - A set of methods defined through defmulti that is used within the >> deftype form act as *abstract methods* >> - The *abstract methods* all dispatch on map keys (usually :type). >> >> >> I am curious if others have found this useful? >> >> Most of the people who work with Clojure have backgrounds with Object >> Oriented Programming, so that paradigm sometimes seems natural, or at least >> familiar. I often think these designs are more verbose than they need to >> be, but I am curious how others feel. >> >> >> >> >> >> >> >> >> >> >> -- >> You received this message because you are subscribed to the Google >> Groups "Clojure" group. >> To post to this group, send email to clo...@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+u...@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+u...@googlegroups.com. >> For more options, visit https://groups.google.com/d/optout. >> >> >> -- 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/d/optout.