Hello,

To be honest I don't see any fundamental difference between your first
attempt and the improvement: both share the fact that the mutation of the
state happens within the draw function. So in both cases, you have a
temporal coupling between updating the state of the app and rendering a new
view of the app's state.

I would suggest that you don't swap! at all within draw, just deref and
render the result of the dereffing.

And, in another thread, at potentially a totally different pace than the
redrawing's pace, update the application's state accordingly to business
rules / constraints.

Schematically, something like this:

(def app-state (atom (init-state)))

(defn draw [...]
  (let [app-snapshot (deref app-state)]
      ... call quil primitives to render the application state snapshot
...))

(future
  ... logic which updates the app-state atom depending on business rules /
constraints, in a separate thread ...)


HTH,

-- 
Laurent



2014-03-09 13:47 GMT+01:00 J. Pablo Fernández <pup...@pupeno.com>:

> Hello Clojurians,
>
> I'm starting to play with Processing and I want to use my favorite
> programming language for it, so I started using 
> Quil<https://github.com/quil/quil>.
> The problem is that Processing has a imperative architecture and makes my
> Clojure code look bad. For those that don't know Processing/Quil, here's a
> little overview that's relevant to this email.
>
> Processing is a language and a library that makes it easy to draw on the
> screen to do generative art, simulations, etc. Processing programs have two
> methods, a setup method that is run once, at the beginning, and then a draw
> method that is run over and over. Literally something like:
>
> Walker w;
>
> void setup() {
>   w = new Walker();
> }
>
> void draw() {
>   w.render();
>   w.walk();
> }
>
> I'm using a hypothetical walker, an entity that walks around the screen.
> More or less taken from here: http://natureofcode.com/book/introduction/
>
> My understanding is that the equivalent Clojure code using Quil would look
> like this:
>
> (defn setup []
>   (set-state! :walker (atom (create-walker))))
>
> (defn draw []
>   (render-walker @(state :walker))
>   (swap! (state :walker) walk))
>
> Quil stores a map in the meta-data of the Processing applet and let's you
> access it. Since I need the state to change, I'm storing the walker in an
> atom. I found examples out there following more or less this structure. I'm
> not happy with this structure, it doesn't feel functional enough.
>
> When thinking about this, I got reminded of Erlang processes, specially
> with OTP, where you have a function that's called over and over to which
> the state is passed and which returns the next state. Following that
> structure I would like to implement it like this:
>
> (defn setup []
>   [(create-walker)])
>
> (defn draw [walker]
>   (render-walker walker)
>   [(walk walker)])
>
> The result of calling setup is a vector containing the attributes to draw,
> and the result of draw is a vector containing the attributes that will be
> used in the next call to draw.
>
> Does this make sense? Does it look cleaner to you guys?
>
> I achieved that by writing this wrappers for setup and draw:
>
> (defn setup-wrapper []
>   (set-state! :state (atom (setup))))
>
> (defn draw-wrapper []
>   (swap! (state :state)
>          (fn [s] (apply draw s))))
>
> My concern with this is that now the whole state is in one single atom
> that I'm replacing on each frame and that might not be good. Is it copying
> the whole state or can Clojure use its copy-on-demand feature even for
> atoms? Is there a better way of doing this?
>
> Thanks.
>
> --
> 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.

Reply via email to