I feel like you would be better off separating functions from the data they 
operate on here. In this case, you could represent the state of a stopwatch 
with a map containing the start time and the time elapsed, and have 
functions `stop`, `reset`, `start`, etc that take the stopwatch data 
structure as an argument and compute an answer or return a new stopwatch 
data structure as needed. If you need to share the state of the stopwatch 
you can always put that map in an atom when you need to.

This has the additional benefit that you can implement new functions on the 
stopwatch without changing the implementation stopwatch data structure 
itself, while in the case of the closure you need to change the 
implementation of `new-stopwatch` if you want to be able to do anything 
else with the stopwatch data - sort of the same rationale for 
clojure.core's extensive use of functions that operate on seqs instead of 
many specialized data structures.

You don't gain much by storing the state in a closure unless you need to 
guarantee that the user of your code can't access it, which with immutable 
data structures isn't often necessary.

-Logan


On Saturday, December 10, 2016 at 2:47:34 AM UTC-5, 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.

Reply via email to