This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
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
you'd think it would, wouldn't you?
Hi. Does anybody have a lot of experience with clojure.java.jdbc? 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
Ok, raised an issue in Jira. Just as a side-note: clojure.java.jdbc 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 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
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.
Gotcha.
@coyotespike: if you a new to clojure and re-frame then there are a lot of concepts and terminology at play
I'm coming up with a better example of my question about vars and atoms...
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
swap! applies a fn- that code is bad
(def foo (atom 42))
=> #'play.core/foo
foo
=> #object[clojure.lang.Atom 0x1a59d8b {:status :ready, :val 42}]
@foo
=> 42
(swap! foo inc)
=> 43
@foo
=> 43
@alexmiller - you're right, I corrected that in REPL, but not before pasting original.
Sorry!
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?
Its value
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
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
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?
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.
I love those channels...like the Clojure community in general, they're very helpful.
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.
Discussion of multiline docstrings here: https://github.com/bbatsov/clojure-style-guide/issues/43
My statement that they're "allowed" to go either way is not quite accurate. See weavejester's comments here: https://news.ycombinator.com/item?id=5819487