Fork me on GitHub

if you do (alter-var-root foo #(* % 2)), it will apply the function #(* % 2) to the value of foo and set foo to that value. In this case, if foo is 2 before, it will be 4 after. set! can only be used for global vars, and will evaluate the expression, rather than applying it. (set! global-var #(* % 2)) will actually change the definition of global-var to the anonymous function: (global-var 2) will evaluate to 4 after the set!.


@lucien.knechtli: right, I understand all of that. What I wanted to know is if the need is to change a global var and the new value can simply be applied, then either set! or alter-var-root can do the job, but is there any difference in choosing one over the other? I've seen both used in the wild.


The official docs say this about set!:

When the first operand is a symbol, it must resolve to a global var. The value of the var's current thread binding is set to the value of expr. Currently, it is an error to attempt to set the root binding of a var using set!, i.e. var assignments are thread-local.


I think that the main difference in this case is that alter-var-root is an atomic operation. Set! Doesn't claim to be.


I thought that at first as well, but I think set! is also atomic but it has to do with threading.


using set! on a global var does not set the root binding of that var, instead it alters the current thread-local binding of that var


Vars provide a mechanism to refer to a mutable storage location that can be dynamically rebound (to a new storage location) on a per-thread basis. Every Var can (but needn't) have a root binding, which is a binding that is shared by all threads that do not have a per-thread binding. Thus, the value of a Var is the value of its per-thread binding, or, if it is not bound in the thread requesting the value, the value of the root binding, if any.


Copied from docs


I think that yes, set! Would only affect the current thread


I wonder why alter-var-root doesn't have a bang suffix: alter-var-root!?


you'd think it would, wouldn't you?


@meow: set! is thread local, alter-var-root is not.


Hi. Does anybody have a lot of experience with I tried to use a prepared update statement and it took me some hours to find out, how to actually use it and that I have to explicitly have to pass true for transaction? which is an optional parameter and only checked for String


Would a PR be interesting that improves checking for the type of call?


Oh, hang on, that is an official clojure project. So, no PR but Jira etc...


Ok, raised an issue in Jira. Just as a side-note: works with DB2, too. At least I didn't encounter problems so far.


Vars, atoms, and macros Suppose I have a var, bound to a reaction which updates when another reaction changes. (A subscription in the re-frame design pattern is just a reaction, which is to say an atom).


(def total-days-selected (reaction (days-between @(subscribe [:date-moved-out]) today)))


This works correctly - I can use the var total-days-selected elsewhere, and it updates based on the most current value of subscribe [:date-moved-out] (which, remember, is just a reaction).


However, suppose I put the subscription in a var: (def start-date (subscribe [:date-moved-out])).


Now, when I use this var, like so: (def total-days-selected (reaction (days-between @start-date today)))


then I find that total-days-selected does not update properly.


I've had this problem elsewhere. In general, it seems that binding an atom in a var, and then using that var in other vars, means that the client vars won't have access to the right value of the atom in the var.


1. Does wrapping an atom in a var, and then wrapping that var in other vars, evaluate the atom's value right then and "store" it?


In other words, does using an atom in this way "freeze" its value?


This problem also occurs when in let statements, by the way.


2. How do I get the atom's value at runtime? Use macros? So far I am just learning to avoid vars.


@coyotespike: I haven't done that much with re-frame, but from what I remember I think you've got a few things mixed up here.


I don't think a reaction is an atom.


You get the value of an atom by dereferencing it, usually using @.


Reagent has a variation of an atom, a reactive atom or ratom.


I feel pretty mixed up, and any clarification is welcome 😉


I believe a reaction is an atom, which updates its value upon another atom's change in value.


My broader question is just how atoms are used. If I put in an atom in a var, then dereference that var inside another var, then update the original atom, the second var doesn't see that change.


The second var, the one relying on the atom var, can be bound through a let or a def - either way, it doesn't see the change to the atom var.


You should be able to bind the atom from (subscribe) via a let - that’s the encouraged way throughout re-frame’s documentation


A reaction is not an atom.


The 2nd building block, reaction, acts a bit like a function. It's a macro which wraps some computation (a block of code) and returns a ratom holding the result of that computation.

The magic thing about a reaction is that the computation it wraps will be automatically re-run whenever 'its inputs' change, producing a new output (return) value.


@meow Thanks for that - so the result of a reaction is a ratom, but it is not itself a ratom.


I believe a reaction is more like a watcher on an atom.


@coyotespike: if you a new to clojure and re-frame then there are a lot of concepts and terminology at play


it gets mighty confusing


I'm coming up with a better example of my question about vars and atoms...


atom is just a special var in a way


Okay, here we go...although I think I understand slightly better already.


(def my-atom (atom 2))


(def atom-client (+ 1 @my-atom))


(swap! my-atom 3)


atom-client still returns 3, not 4.


Because otherwise atom-client wouldn't be immutable...


@coyotespike: yes, but not for that reason

Alex Miller (Clojure team)20:07:59

swap! applies a fn- that code is bad


what do you do in line 2?


and what alex said


(def foo (atom 42))
=> #'play.core/foo
=> #object[clojure.lang.Atom 0x1a59d8b {:status :ready, :val 42}]
=> 42
(swap! foo inc)
=> 43
=> 43


@alexmiller - you're right, I corrected that in REPL, but not before pasting original.


Okay - I want atom-client's value to change when my-atom's value changes.


you understand that @ is the same as (deref ...) and when you deref an atom you get what?


right, and that value is now independent of its origin


doesn't know, doesn't care, from where it came


That makes so much sense it seems painfully obvious now...just wasn't obvious when I was debugging 😉


So I could make atom-client a function, which takes an atom as argument

Alex Miller (Clojure team)20:07:50

Generally it's best to write the vast majority of your functions as pure data transformations from value to value


with an atom, or reagent/atom, or any of the "reactive" atoms you just have to be aware of when you need to deref the atom to get its value and when deref'ing is actually a mistake because then you lose the "magic" auto-updating that reagent and re-frame and such add onto the atom semantics

Alex Miller (Clojure team)20:07:19

And then have a thin layer at the top that applies those functions to your stateful reference


@meow Nicely put - helps place what I've wound up doing in context


@alexmiller - so I should beware of functions which depend on atoms?

Alex Miller (Clojure team)20:07:49

I think you should strive to minimize the number of functions that depend on state


@alexmiller - writing that down, and will contemplate where/how to apply that as a general pattern.


while alexmiller's advice is correct, in re-frame you are dealing with state a lot and some of that involves functions that pass around atoms/ratoms and so you do need to understand the difference between passing an atom vs. passing the value of the atom gotten via deref


@meow - yeah, definitely, and I feel better equipped to do that now


Many thanks to you both. After a couple debugging sessions I figured out that I was missing something fundamental about using atoms and vars at runtime.


It feels good to have sifted through that confusion.


@coyotespike: cool. There are also #C073DKH9P and #C0620C0C8 channels for followup. simple_smile


I love those the Clojure community in general, they're very helpful. simple_smile


Is there style guide for writing doc strings?


I haven't found an official one. I believe they should come before rather than after the parameters, though they're allowed to go either way.


My statement that they're "allowed" to go either way is not quite accurate. See weavejester's comments here: