Two clojure cards are displayed as elements of each other
I have two cards in links and would like to link them to each other in one transaction.
My function looks like this:
(defn assoc-two
[one two]
(let [newone (assoc @one :two two)
newtwo (assoc @two :one one)]
(ref-set one newone)
(ref-set two newtwo)))
Now I am calling assoc-two
like this:
(dosync (assoc-two (ref {}) (ref {})))
Im get and StackOverflowError at this point.
I also tried this:
(defn alter-two
[one two]
(alter one assoc :two two)
(alter two assoc :one one))
Is it possible to do this so that it one
has a link that refers to two
and vice versa and is still in the same transaction?
source to share
Stack overflow does not occur until you try to print one of the circular references, for example. at the REPL.
so.core => (def a (ref {})) # 'so.core / a so.core => (def b (ref {})) # 'so.core / b so.core => (do (dosync (alter-two ab)): success) : success so.core => (= b (: two @a)) true so.core => (= a (: one @b)) true
Obviously printing an object with circular references like this would be problematic, but see this recent question and answer about disabling default printing of reference types
(remove-method print-method clojure.lang.IDeref)
(dosync (alter-two (ref {}) (ref {})))
;=> {:one #<Ref clojure.lang.Ref@7f1f91ac>}
; (prints the second ref without attempting to print its circular contents)
source to share
The answer can be found in several posts, it's just a REPL trying to print your recursive structure. You need to either remove the print method:
(remove-method print-method clojure.lang.IDeref)
Or add a print method that handles your specific case, this method should be more specific than normal clojure.lang.IDeref
source to share