Clojure equivalent of special common lisp vars: still looking for that zen place...

150 views
Skip to first unread message

Dave Tenny

unread,
May 3, 2014, 9:45:48 AM5/3/14
to clo...@googlegroups.com
I'm still struggling with how to write the most readable, simple clojure code
to deal with dynamically bindings.

What is the graceful clojure equivalent of common lisp special variables for the following scenario.

If I were writing common lisp I'd just do something like (pardon if my lisp is rusty here):

(defvar *x* 1)
... do stuff with *x* ...
(setq *x* 2)
... do stuff with *x* ...
(let ((*x* 3))  (do stuff with *x*...)
;; do stuff with *x* that's currently at 2


The way I'm tempted to do this in clojure is

(def ^{:dynamic true} *x* (atom 1))
... do stuff with @*x* ...
(reset! *x* 2)
... do stuff with @*x* ...
(binding [*x* (atom 3)] (do stuff with @*x*))


Is that the simplest way to map between the two language scenarios?
Or is there something simpler, perhaps using some var-* apis or what have you?


Bob Hutchison

unread,
May 3, 2014, 10:53:40 AM5/3/14
to clo...@googlegroups.com
On May 3, 2014, at 9:45 AM, Dave Tenny <dave....@gmail.com> wrote:

I'm still struggling with how to write the most readable, simple clojure code
to deal with dynamically bindings.

What is the graceful clojure equivalent of common lisp special variables for the following scenario.

If I were writing common lisp I'd just do something like (pardon if my lisp is rusty here):

(defvar *x* 1)
... do stuff with *x* ...
(setq *x* 2)
... do stuff with *x* ...
(let ((*x* 3))  (do stuff with *x*...)
;; do stuff with *x* that's currently at 2


The way I'm tempted to do this in clojure is

(def ^{:dynamic true} *x* (atom 1))
... do stuff with @*x* ...
(reset! *x* 2)
... do stuff with @*x* ...
(binding [*x* (atom 3)] (do stuff with @*x*))

Inside the binding you can call set! if you must.

You can also just use ‘def’ to redefine the global binding. It says this:

Using def to modify the root value of a var at other than the top level is usually an indication that you are using the var as a mutable global, and is considered bad style. Consider either using binding to provide a thread-local value for the var, or putting a ref or agent in the var and using transactions or actions for mutation.” in the docs at http://clojure.org/special_forms#def which is roughly what you did with the atom. But it’ll work.

You can also just write it:

(def ^:dynamic *x* (atom 1))

which is a little less verbose.

Cheers,
Bob



Is that the simplest way to map between the two language scenarios?
Or is there something simpler, perhaps using some var-* apis or what have you?



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

Lee Spector

unread,
May 3, 2014, 11:08:27 AM5/3/14
to clo...@googlegroups.com

On May 3, 2014, at 9:45 AM, Dave Tenny <dave....@gmail.com> wrote:
>
> The way I'm tempted to do this in clojure is
>
> (def ^{:dynamic true} *x* (atom 1))
> ... do stuff with @*x* ...
> (reset! *x* 2)
> ... do stuff with @*x* ...
> (binding [*x* (atom 3)] (do stuff with @*x*))


Having also come from Common Lisp and having once done things similar to your suggestion in Clojure, I got burned by the fact (I *think* it was a fact) that "binding" created thread-local bindings that reverted to global bindings inside of code executed in another thread, e.g. in a pmap buried somewhere within the code executed within the binding form. I found this to be unexpected and problematic.

Trying some simple examples with your outline, however, I don't see this happening. And I wonder if it's because of changes in more recent versions of Clojure related to ^{:dynamic true}.

Does anyone know if the reversion of "binding"-bound vars to global bindings when crossing thread boundaries has really been eliminated? Or am I just not seeing it because my examples have been too simple?

-Lee

Dave Tenny

unread,
May 3, 2014, 11:09:29 AM5/3/14
to clo...@googlegroups.com

On Sat, May 3, 2014 at 10:53 AM, Bob Hutchison <hutch...@recursive.ca> wrote:
You can also just use ‘def’ to redefine the global binding.


Thanks, though in this case it's a mixed use.  In some cases I want to change the root of the global binding, in others I want to rebind to a new value in some context without changing the value seen in other contexts.

Dave Tenny

unread,
May 3, 2014, 11:12:08 AM5/3/14
to clo...@googlegroups.com
re: binding behavior, I've only been using clojure since 1.5.1, but in my travels I get the impression that the binding form didn't always enforce the variable to be declared dynamic, and so maybe didn't behave the way you'd expect if the ^:dynamic was missing from the target of the binding form.  Just guessing.


--
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 a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/Wh1M345Y5u4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojure+u...@googlegroups.com.

John Gabriele

unread,
May 5, 2014, 1:38:46 PM5/5/14
to clo...@googlegroups.com
On Saturday, May 3, 2014 10:53:40 AM UTC-4, Bob Hutchison wrote:

On May 3, 2014, at 9:45 AM, Dave Tenny <dave....@gmail.com> wrote:

I'm still struggling with how to write the most readable, simple clojure code
to deal with dynamically bindings.

What is the graceful clojure equivalent of common lisp special variables for the following scenario.

If I were writing common lisp I'd just do something like (pardon if my lisp is rusty here):

(defvar *x* 1)
... do stuff with *x* ...
(setq *x* 2)
... do stuff with *x* ...
(let ((*x* 3))  (do stuff with *x*...)
;; do stuff with *x* that's currently at 2


The way I'm tempted to do this in clojure is

(def ^{:dynamic true} *x* (atom 1))
... do stuff with @*x* ...
(reset! *x* 2)
... do stuff with @*x* ...
(binding [*x* (atom 3)] (do stuff with @*x*))

You can also just write it:

(def ^:dynamic *x* (atom 1))

which is a little less verbose.


My understanding is that it's more common to *either*

  * use `(def ^:dynamic *x* 1)`, *or*
  * use `(def x (atom 1))`,

but not both at the same time.

That is to say, either you specifically want at dynamic var which you can change via a `binding`, or else you just want a global mutable (the atom).

Would love to be corrected if I'm wrong though.

-- John

Gary Trakhman

unread,
May 5, 2014, 1:45:17 PM5/5/14
to clo...@googlegroups.com
Sometimes you do want a mutable thing with thread-local binding, noir does this for it's mutable session-flash stuff: https://github.com/noir-clojure/lib-noir/blob/master/src/noir/session.clj#L95

I don't really recommend the approach, but I could see it being convenient.


Reply all
Reply to author
Forward
0 new messages