Variable assignment(?) in Clojure

3,694 views
Skip to first unread message

prathamesh sonpatki

unread,
Feb 13, 2013, 2:05:52 AM2/13/13
to clj-...@googlegroups.com
Hi,
What exactly happens if i try to define same variable with two different values. For eg;

(def a 1)
; Now a is 1

(def a 2)
; Now a is 2

So, is it a assignment operation or new a getting created?

-- 
./prathamesh

Baishampayan Ghose

unread,
Feb 13, 2013, 2:36:12 AM2/13/13
to clj-...@googlegroups.com
Hi,

Let's adopt some new terminology before we proceed.

When we say (def foo 42) it creates a new "binding" of the symbol
"foo" with the value 42.

What really happens is that the symbol "foo" now "points" to the value 42.

Once a binding has been created, there is no way to mutate value
pointed to by its binding. As a result, it's also possible for
multiple such bindings to point to the same value (identical in some
cases).

When you say (def foo 55) again it creates a new binding for the
symbol "foo" and the value 55.

That doesn't mean you've mutated or changed the underlying value; any
other bindings pointing to the same location will still hold the same
reference and will still be consistent.

So while it's not an assignment operation in the traditional sense,
but it does introduce a side-effect, that of creating a new binding
and shadowing the old one.

Hope that helps.

Regards,
BG
> --
> You received this message because you are subscribed to the Google Groups
> "Clojure Users Group Pune" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clj-pune+u...@googlegroups.com.
> Visit this group at http://groups.google.com/group/clj-pune?hl=en.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>



--
Baishampayan Ghose
b.ghose at gmail.com

Ravindra Jaju

unread,
Feb 13, 2013, 2:39:46 AM2/13/13
to clj-...@googlegroups.com
Well, in very simple terms, that is an assignment!

I'll explain in terms of how I understand it :)

(def a) creates a "var" object (java class name: Var - noisy detail, if that interests you)
It's like a "pointer to a pointer" and internally points to an actual "value" if supplied.

So, (def a) will create an "unbound" var.
(def a foo) will fail if there's no foo accessible in the namespace, or if foo is another var, the value will be fetched from it and assigned to a.

(def a) ; Unbound a
(def a 10) ; Same a now bound to a value "10"
(def a 20); Same a now bound to a value "20"

(def b a) ; b now contains the value 20
(def a 30) ; a contains 30
b ; still 20

A var's value is obtained by "dereferencing" it.
(def a 10)
a ; clojure fetches the stored value 10
#'a ; now, it's the first pointer in the "pointer to pointer" - so, that's the "Var" a
@#'a ; 10 - same as a

Interesting tidbit:
(.bindRoot #'a 100) ; is the same as (def a 100) for an already defined Var a.

Hope this helps.

--
jaju

On Wed, Feb 13, 2013 at 12:35 PM, prathamesh sonpatki <cson...@gmail.com> wrote:

--

prathamesh sonpatki

unread,
Feb 13, 2013, 2:54:09 AM2/13/13
to clj-...@googlegroups.com
 When you say (def foo 55) again it creates a new binding for the
 symbol "foo" and the value 55.


So each binding is independent of each other
 
That doesn't mean you've mutated or changed the underlying value; any
other bindings pointing to the same location will still hold the same
reference and will still be consistent.

 
So if i am in the first scope again then i can refer to old binding. But if they are in same scope then second binding shadows first one.

So while it's not an assignment operation in the traditional sense,
but it does introduce a side-effect, that of creating a new binding
and shadowing the old one.


Thanks. Makes sense now.



--
./prathamesh

Baishampayan Ghose

unread,
Feb 13, 2013, 5:49:25 AM2/13/13
to clj-...@googlegroups.com
Well, if you use `def` then you're changing the root (aka global)
binding, so everyone will see the new binding. Clojure provides ways
of creating new bindings/reset bindings that are "thread-local" so the
newly bound value is only visible in that thread. ~BG

On Wed, Feb 13, 2013 at 1:24 PM, prathamesh sonpatki

letronje

unread,
Feb 15, 2013, 12:35:38 AM2/15/13
to clj-...@googlegroups.com

letronje

unread,
Feb 18, 2013, 2:04:18 PM2/18/13
to clj-...@googlegroups.com
Also, vars aren't thread safe https://gist.github.com/letronje/4979590

- deffing a var appears to be slower than swapping an atom
- Each thread running var-incrementer takes up around 60-80% of each core on my 4 core machine.
But each atom-incrementer thread takes up almost 98-100% :)

Baishampayan Ghose

unread,
Feb 18, 2013, 7:58:49 PM2/18/13
to clj-...@googlegroups.com
Manoj,

I laughed when read the statement about vars not being "thread-safe".
Of course they "seem to be" not thread-safe because apparently you
don't understand what vars are and how they are meant to be used.

You're "never" supposed to `def` vars to "set" their bindings because
vars are meant to be used for "thread-local" bindings and not for
"bashing in place" like a variable. Your var example is actually no
different than setting a global variable from two threads and watching
them become inconsistent in _any_ language.

The main use-case of vars is to change the binding temporarily in a
thread-local manner such that only a single thread sees the changed
binding while executing while others see the root or other temporary
bindings.

You can dynamically change the binding of a var "properly" either
through "binding" or by "set!" (you'd need that var to be declared
dynamic for this). If you want to change the "root" binding, then
you're supposed to use "alter-var-root".

As such, your example is a contrived example of "how not to use a var"
and shows the pitfalls of bashing a variable in place reasonably well.

Now the question remains, "why does Clojure allow vars to be deffed
like that?". Well, that's because in Clojure functions are held inside
vars and it's useful to recompile functions when a system (like the
REPL) is running, right?

Anyway, if you still wish to try out the "thread-safety" of vars, you
need to change your `var-incrementer` functions to this -

(defn var-incrementer [d]
(dotimes [_ 2e7]
(alter-var-root #'v inc)))

Try it out and let me know if you find more "bugs" in Clojure like this :)

Regards,
BG

letronje

unread,
Feb 18, 2013, 10:52:18 PM2/18/13
to clj-...@googlegroups.com
That wasn't supposed to come across as a bug report on clojure vars :)

I know vars aren't supposed to be used like that. I'd read somewhere that clojure vars aren't thread safe and thought I'd try vars and threads together. What better way to learn clojure than to play with it eh :) 

I'll check out alter-var-root, thanks.

Baishampayan Ghose

unread,
Feb 18, 2013, 11:34:01 PM2/18/13
to clj-...@googlegroups.com
Manoj,

I don't know where you read about vars not being thread-safe and the
context thereof, but I can tell you with certainty that vars are
definitely thread-safe (just like anything else in Clojure) provided
you use them the they were intended to be used.

If you look at your code, you'll notice the line - (def v (inc v))

That construct itself is a dead-giveaway that what you're doing can't
be right. You're doing two things here, reading the "current" value,
incrementing it & then setting it back.

The point is, in a concurrent system there is no notion of "current"
and any attempt to reset the binding after fetching will give rise to
race condition as you're doing two things which could/will be
interleaved in a concurrent scenario.

As a matter of fact I am not aware of any programming language that
can support such a construct safely (discounting locks as that
enforces the notion of a serialised world).

The right way is of course to send it a function which will be applied
to whatever the binding is when its executed.

Hope that helps.

BG

manoj mathai

unread,
Feb 18, 2013, 11:52:02 PM2/18/13
to clj-...@googlegroups.com
A follow up question would be that since functions are held within vars, Can there be issues when hot-reloading heavily used functions(for e.g. a function called in the path of every request coming into a high traffic web app) inside a running jvm ?




Microsoft gives you Windows, Linux gives you the whole house...

Baishampayan Ghose

unread,
Feb 19, 2013, 12:04:20 AM2/19/13
to clj-...@googlegroups.com
The asker/answerer conflated two different concepts, thread-safety and
side-effect. Another reason to not trust StackOverflow answers.

To answer your question, hot-code reloading is thread-safe (doesn't
matter if the function is heavily used, alter-var-root is atomic), but
recursive functions may get screwed up (in the sense that it will
still use the old function) if it holds a reference to the old
function and the root binding changes mid-execution. Subsequent
executions will see the new function.

Not very different from even Erlang in practical terms.

Regards,
BG

Ravindra Jaju

unread,
Feb 19, 2013, 12:04:52 AM2/19/13
to clj-...@googlegroups.com
So, again, it all depends on how you use those vars.

When you hold functions or concurrency-friendly structures in them, you are only defining them once at "start up time."
Post that, you use the "right way" to swap values, with specific guarantees on behaviour and visibility.

In a hot-reloading-of-a-new-definition-of-functions scenario, the change is only beyond a point in time before which you
used the old definition and after which, a new one. And functions are just "immutable values" and the change is atomic.
So, if your application is architected in a way which allows re-definition, you are still going to be fine. Depends on the context.

HTH.

--
jaju

On Tue, Feb 19, 2013 at 10:22 AM, manoj mathai <manojp...@gmail.com> wrote:

letronje

unread,
Feb 19, 2013, 4:27:44 AM2/19/13
to clj-...@googlegroups.com
alter-var-root works, thnx :)


On Tuesday, February 19, 2013 6:28:49 AM UTC+5:30, Baishampayan Ghose wrote:
Reply all
Reply to author
Forward
0 new messages