Sure, that makes sense. I'll give that a go along with a few other ideas, and see what works out best. Thanks for the help!
Andrew Oberstar On Sun, Mar 15, 2015 at 1:22 PM Colin Yates <colin.ya...@gmail.com> wrote: > I don't have one at hand (as I literally wrote my first macro last > week ;)) but the way it could work is something like: > > (defmacro idempotent-component > [{:keys [name start started? stop]}] > `(defrecord (symbol name) [...] > component/Lifecycle > (start [this#] > (if (~'started? this#) > this# > (~' this))) > (stop [this#] > (if (~'started? this#) > (~`stop this#) > this))) > > and called like > > (idempotent-component {:name "SillyExample" start: println started?: > (constantly true) stop: println}) > > There are probably a 100 things wrong with that macro and possiblly > even the idea of using a macro here, but hopefully it opens up the > possibilities. > > On 15 March 2015 at 17:40, Andrew Oberstar <ajobers...@gmail.com> wrote: > > Thanks, Colin. Macros hadn't crossed my mind, so it's good to have them > > pointed out. Do you have a macro you could post that is a good example of > > enforcing a pattern as an implementation detail? I think that's a good > > general consideration, but I don't believe it fits this use case. Though > an > > example may be more illuminating. > > > > In some ways, this use case seems akin to the implementation of nth in > > ClojureScript, where it's exact behavior can differ depending on the > > protocols satisfied by the passed collection. > > > > Looking back through the component docs, update-system and > > update-system-reverse may be the key piece for implementing something > like > > the LifecycleStatus solution in my original email without requiring any > > change to component itself. The big weakness is that it would require > using > > a custom start-system stop-system function rather than the standard one. > > > > Andrew Oberstar > > > > On Sun, Mar 15, 2015 at 11:32 AM Colin Yates <colin.ya...@gmail.com> > wrote: > >> > >> In OO we tend to solve the 'copy and paste' problem with abstract > >> classes. In Clojure we also have macros, easily overused, sure, but > >> worth knowing about. They turn the problem on its head and allow truly > >> composable functionality. I am not stating they _are_ appropriate > >> here, only that you might want to think about them; whenever I have a > >> 'I want this pattern enforced, but it is really just an implementation > >> detail', a macro is sometimes the answer. > >> > >> On 15 March 2015 at 15:58, Andrew Oberstar <ajobers...@gmail.com> > wrote: > >> > I'm fairly new to Clojure, so I'm still struggling to unlearn the > habits > >> > of > >> > OO-programming. While using Stuart Sierra's component library, I've > >> > found > >> > the recommendation in the docs of using idempotent lifecycles very > >> > helpful. > >> > The unfortunate result is that every component then has the same > pattern > >> > in > >> > its start and stop methods: > >> > > >> > (defrecord SillyExample [...] > >> > component/Lifecycle > >> > (start [this] > >> > (if (custom-started-check? this) > >> > this > >> > (custom-start-logic this))) > >> > (stop [this] > >> > (if (custom-started-check? this) > >> > (custom-stop-logic this) > >> > this))) > >> > > >> > It adds some extra nesting and, potentially, duplication of the > started > >> > check's logic. In hopes of making idempotent lifecycles easier to > >> > implement, > >> > I made the following protocol, which seems to violate the > implementation > >> > inheritance philosophy of Clojure. > >> > > >> > (defprotocol IdempotentLifecycle > >> > (started? [this]) > >> > (safe-start [this]) > >> > (safe-stop [this])) > >> > > >> > (extend-protocol component/Lifecycle > >> > my.ns.IdempotentLifecycle > >> > (start [this] > >> > (if (started? this) > >> > this > >> > (safe-start this))) > >> > (stop [this] > >> > (if (started? this) > >> > (safe-stop this) > >> > this))) > >> > > >> > So then a use case would like more like: > >> > > >> > (defrecord SillyExample [...] > >> > IdempotentLifecycle > >> > (started? [this] > >> > (custom-started-check this)) > >> > (safe-start [this] > >> > (custom-start-logic this)) > >> > (safe-stop [this] > >> > (custom-stop-logic this))) > >> > > >> > This seems like an easier end-user experience, but it feels wrong to > >> > implement a protocol with another protocol. A more "Clojurey" feeling > >> > option > >> > would require changes to the component library itself: > >> > > >> > (defprotocol LifecycleStatus > >> > (started? [this])) > >> > > >> > (extend-protocol LifecycleStatus > >> > java.lang.Object > >> > (started? [_] false)) > >> > > >> > ;; Lifecycle protocol stays as-is > >> > > >> > (defn safe-start [component] > >> > (if (started? component) > >> > this > >> > (start component))) > >> > > >> > (defn safe-stop [component] > >> > (if (started? component) > >> > (stop component) > >> > this)) > >> > > >> > Then component would need to use safe-start/safe-stop in place of > >> > regular > >> > start/stop in the start-system/stop-system functions. > >> > > >> > Maybe this is better suited to an issue/pr on his repository, but I > >> > wanted > >> > to see if there were any comments from the community. Is there a > better > >> > way > >> > to do this? > >> > > >> > Andrew Oberstar > >> > > >> > -- > >> > 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. > >> > >> -- > >> 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. > > > > -- > > 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. > > -- > 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. > -- 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.