Question

I feel like I'm missing something about the use of refs, something under the hood that isn't happening like I think it is. I'm making a thread-safe double linkedlist where the list is a hash containing refs to head and tail. A node of the list is represented by a hash containing previous, next and value.

(defn insert
  [list elem]
  (dosync
    (let [head @(:head list)]
      (if (nil? head)
        (do (ref-set (:head list) elem)
          (ref-set (:tail list) elem))
        (do
          (ref-set (:head list) elem)
          (ref-set (:next elem) head);;fails!
          (ref-set (:prev head) elem))))));;fails!

This gives me a StackOverflow error. To be exact:

StackOverflowError java.util.regex.Pattern$Curly.match

It feels like I miss something in how refs work in Clojure, can anybody tell me what's wrong?


EDIT: Here is a link to the full "code". https://www.refheap.com/6544630b38b33b9d25d999829 it fails on the last line, in the else clause of the insert function, when the head is not null anymore.

(def f (create-doubly-linked-list))
(def n (create-node 2))
(insert f n)
(def m (create-node 3))
(insert (f m);;error!

Note that the error manifests when I try to access the list, or ie when I evaluate f in the repl, or when I execute the last line in the REPL.


UPDATE: Following code works, but accessing the list causes problems as well as printing it.

(def f (create-doubly-linked-list))
(def n (create-node 2))
(insert f n)
(insert f (create-node 5))
(insert f (create-node 1))
(def m (create-node 3))
(insert f m)

(is (= @(:value @(:tail f)) 2))
(is (= @(:value @(:head f)) 3))
Was it helpful?

Solution

It seems that the code is correct, but caused a stackoverflow due to trying to evaluate the list. Since the list has cyclic references, (previous and next), it isn't possible to 'evaluate' it, hence causing the error.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top