Logan's point about being able to add new functions on a stopwatch is valid. That's often the argument to why protocols are better then classic OO. Though I still feel like in some scenarios, I think this is a good pattern, and can serve us better, the stopwatch being one good example.
Nothing in the pattern necessitate this to be mutable either, though I guess this pattern does seem to have some of its advantages from when you need mutability for some reason. Then I like how it isolates the mutable data behind the functionality. It feels like a lighter weight version of both OO and protocols/records. I'm curious to benchmark it against records, which is what I would have used before for something like a stopwatch. I think this could come in handy when doing libraries with options. My current pattern was to have a function create an options, and then the user would need to manage the options map, and pass it to all my library functions. Or I would use a var instead the library to store the options map, and offer it as a binding so users could rebind their own options. The problem with the latter is that you can't run the library with two different option set at the same time, while the former forces you to have to manage an options map and pass it around everywhere. So I feel there's something I could do here, with wrapping everything in this pattern, and having the options be captured in the closure. On Friday, 9 December 2016 23:47:34 UTC-8, Didier wrote: > > I'm wondering what everyone thinks of using closures to mimic a simplistic > object system in Clojure? I'm not sure what to think of it yet, but the > idea is that you wrap object fields inside a closed function, and it > returns a map of methods that operates over those fields. > > Here's an example of using this pattern to implement a StopWatch: > > (import [java.lang System]) > (defn new-stopwatch [] > (let [start-time (atom nil) > elapsed (atom 0)] > {:start (fn [] > (when (nil? @start-time) > (reset! start-time (System/currentTimeMillis)))) > :stop (fn [] > (when-not (nil? @start-time) > (reset! elapsed > (+ @elapsed > (- (System/currentTimeMillis) @start-time))) > (reset! start-time nil)) > @elapsed) > :reset (fn [] > (reset! start-time nil) > (reset! elapsed 0) > @elapsed) > :elapsed (fn [] > (if-not (nil? @start-time) > (- (System/currentTimeMillis) @start-time) > @elapsed))})) > > (let [sw1 (new-stopwatch) > sw2 (new-stopwatch)] > ((:start sw1)) > ((:start sw2)) > (Thread/sleep 100) > ((:reset sw1)) > ((:start sw1)) > (println (str "Elapsed for SW1: " ((:elapsed sw1)))) > (println (str "Elapsed for SW2: " ((:elapsed sw2)))) > (Thread/sleep 100) > (println (str "SW1: " ((:stop sw1)))) > (println (str "SW2: " ((:stop sw2))))) > > I find for certain things, like a stopwatch, this pattern is actually > pretty nice. I can't think of any alternative way to do this in Clojure > that I'd like better actually. > > What are your thoughts? > -- 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.