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?

+3


source to share


2 answers


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)

      

+6


source


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

+2


source







All Articles