local mutable state

384 views
Skip to first unread message

Andy Smith

unread,
Mar 20, 2014, 3:34:20 PM3/20/14
to clo...@googlegroups.com

Is is very bad form to use local mutable state to solve problems like :

https://www.4clojure.com/problem/114

i.e.

(fn [n f xs] (let [c (atom 0)] (take-while #(if (f %) (> n (swap! c inc)) true) xs)))

If so, what is the strongest reason to reject this kind of code? Since its a local atom it ought to be thread-safe right?

Thanks

Andy

Jacob Goodson

unread,
Mar 20, 2014, 4:24:41 PM3/20/14
to clo...@googlegroups.com
I suggest using proteus https://github.com/ztellman/proteus for performant local mutation.

James Reeves

unread,
Mar 20, 2014, 4:26:12 PM3/20/14
to clo...@googlegroups.com
There are a few reasons to reject this style of code:

1. It's typically less performant.
2. It's more prone to error.
3. It's not particularly idiomatic.

Also, as this is a learning exercise, I suspect that the question is directing you toward a more functional solution.

- James


--
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.

Timothy Baldridge

unread,
Mar 20, 2014, 4:34:47 PM3/20/14
to clo...@googlegroups.com
Not to mention that this isn't local mutation. You are handing the atom to a closure that then gets wrapped by lazy-seq and returned. So the atom may actually sit around for some time.
--
“One of the main causes of the fall of the Roman Empire was that–lacking zero–they had no way to indicate successful termination of their C programs.”
(Robert Firth)

Andy Smith

unread,
Mar 20, 2014, 4:35:14 PM3/20/14
to clo...@googlegroups.com, ja...@booleanknot.com
Also from the proteus link, i read 'these variables cannot escape the local scope; if passed into a function or closed over', which is a problem with code such as in my example I suppose.

I wasnt trying to avoid the functional approach but just being devils advocate. Thanks for your comments.

P.S. This forum is great. Although I keep asking dumb newbie questions, everyone still gives helpful replies, Thanks all...

Jacob Goodson

unread,
Mar 20, 2014, 4:42:54 PM3/20/14
to clo...@googlegroups.com, ja...@booleanknot.com
You can use proteus with a while loop and be as imperative as you like, however, I think the point of 4clojure is to learn the functional approach to solving problems(I do not really advocate one over the other honestly; multiparadigm ftw)

James Trunk

unread,
Mar 20, 2014, 6:07:45 PM3/20/14
to clo...@googlegroups.com
Hi Andy,

I think Mr. Reeves gave you some excellent reasons to avoid using local mutable state, especially when trying to learn functional programming. If you're interested in seeing a spoiler for 114 you can look at one approach below (if you don't want a spoiler, then close this tab post-haste! ;-)
(fn my-take-while [n pred coll]
  (lazy-seq
    (let [first-element (first coll)
          n (if (pred first-element) (dec n) n)]
      (when (> n 0)
        (cons first-element (my-take-while n pred (rest coll)))))))
Cheers, 
James

Andy Smith

unread,
Mar 21, 2014, 7:44:39 AM3/21/14
to clo...@googlegroups.com
Im also interested as to why the mutable state approach would be less performant? In the single thread case the locks would be optimized out right?

Andy Smith

unread,
Mar 21, 2014, 7:48:24 AM3/21/14
to clo...@googlegroups.com
Excellent point... thanks for the insight

Ben Mabey

unread,
Mar 21, 2014, 12:24:21 PM3/21/14
to clo...@googlegroups.com
On 3/21/14, 5:44 AM, Andy Smith wrote:
Im also interested as to why the mutable state approach would be less performant? In the single thread case the locks would be optimized out right?
No locks are used when using atoms, only compare-and-swap (CAS) operations.  While CAS operations are fast you don't want to use them unless you need to in a multi-threaded system.  Clojure nor the JVM will "optimize out" the use of them in a single-threaded case like this.  They are a very heavy approach when all you need is local mutation.  Clojure doesn't have local mutation out of the box.. it is very opinionated on how state should be handled.  The example solution posted earlier in the thread is more indiciative of how state like this is handled in clojure.

As pointed out earlier in the thread if you wanted/needed to have local mutation you could use https://github.com/ztellman/proteus.  In the vast majority of cases this is unneeded.

-Ben

Jacob Goodson

unread,
Mar 21, 2014, 3:22:46 PM3/21/14
to clo...@googlegroups.com
Also, you can use straight up java as well inside of loops.  I, sometimes, will write a static method, dump the clojure data strcuture over to java, mutate like a crazy man, then slap it back into clojure.  I find that loop recur are not as elegant as imperative styles of looping(an opinion of course).  I think of recursion as a low level operation, it is a outlier in clojure where most of the time we swim in an abstraction bliss.  Anyway, I find using pattern matching in conjunction with recursion makes it far more elegant... https://github.com/clojure/core.match
Reply all
Reply to author
Forward
0 new messages