When an object is built from a map, aggregating mixins is a trivial operation. But when a mixin needs to be closed, it is better to have a common mechanism to manage a stack of the close functions of all the aggregated mixins than to depend on application logic to do so. Case in point, I'd like to use an actor mixin or an alternative async channel mixin when composing a database. The async channel mixin will require a close but the actor mixin will not. So I developed the closer mixin to handle the calls to both the async channel and db file close functions. The database will only know the closer's do-close method. And it is the responsibility of the async channel and the db file mixins to register their close functions with the closer mixin.
My inspiration is Stuart Sierra's component library. But I am not handling dependencies per say, only managing a stack of close functions. And the "components" are only functions and atoms added to a common map structure, not records or deftypes. The result is a very lightweight pattern for components. The closer code itself is a lock-free mixin that gets added to the common map as needed when the on-close method is called.
For more information, see Closer.
(ns aatree.closer
(:require [clojure.tools.logging :as log]))
(set! *warn-on-reflection* true)
(defn on-close [f opts]
(let [fsa (:closer-fsa opts)]
(if fsa
(do
(swap! fsa
(fn [fs]
(if fs
(conj fs f)
(atom (list f)))))
opts)
(assoc opts :closer-fsa (atom (list f))))))
(defn- do-closer [fs opts]
(when fs
(try
((first fs) opts)
(catch Exception e
(log/warn e "exception on close")))
(recur (next fs) opts)))
(defn do-close [opts]
(let [fsa (:closer-fsa opts)]
(if fsa
(let [fs @fsa]
(if fs
(if (compare-and-set! fsa fs nil)
(do-closer fs opts)
(recur opts)))))))
--
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 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 a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/7Q7QvlSUGL4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojure+u...@googlegroups.com.
--
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 a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/7Q7QvlSUGL4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojure+u...@googlegroups.com.
> in this industry there are hardly any unambiguous and objective statementsEither you contradict yourself or the following is ambiguous and/or subjective:
> pragmatism throws it all out of the window
-----> One man’s complexity is another man’s simplicity and so on.Can you please give an example?
-----Are you suggesting we don't discuss merits and shortcomings of different approaches to design software?
For me, the winner is avoiding static structures. I am tired of doing ongoing refactorings interrupted periodically by complete rewrites. Class hierarchies are the worst--being the largest, they are the least stable.
One man’s complexity is another man’s simplicity and so on.
--
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 a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/7Q7QvlSUGL4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojure+u...@googlegroups.com.
James, thanks for recommending Simple Made Easy. As usual, I strongly agree with 95% or more of everything Rich says.While listening to this talk, I kept thinking about why I am avoiding protocols. In general, I very much like having abstractions. But I find that even small abstractions tend to complect what with how.
Protocols are the perspective of the client code. It defines what is there to be used. But they should not be part of the code that provides a service. Rather, they should belong to the aggregate of service providers. Lets look at an example.Suppose we have get and set! functions which an aggregate supports. Normally you would think of get and set! as being implemented by code that implements both. So you define a protocol that has both. It is a small protocol that has nothing else. But it is possible that these are implemented by very different pieces of code within an aggregate.
--
(ns aatree.closer-trait
(:require [clojure.tools.logging :as log]))
(set! *warn-on-reflection* true)
(defn on-close [this f]
(let [fsa (:closer-fsa this)]
(if fsa
(do
(swap! fsa
(fn [fs]
(if fs
(conj fs f)
(atom (list f)))))
this)
(assoc this :closer-fsa (atom (list f))))))
(defn- do-closer [this fs]
(when fs
(try
((first fs) this)
(catch Exception e
(log/warn e "exception on close")))
(recur this (next fs))))
(defn do-close [this]
(let [fsa (:closer-fsa this)]
(if fsa
(let [fs @fsa]
(if fs
(if (compare-and-set! fsa fs nil)
(do-closer this fs)
(recur this)))))))