22

Ignoring native interop and transients, is it possible to create any data structures in Clojure that contain direct circular references ?

It would seem that immutable data structures can only ever contain references to previous versions of themselves. Are there any Clojure APIs that could create a new data structure that has a reference to itself ?

Scheme has the letrec form which allows mutually recursive structures to be created - but, as far as I can tell, Clojure does not have anything similar.

This question is related to porting Clojure to iOS - which does not have garbage collection, but does have reference counting.

Abhinav Sarkar
  • 23,534
  • 11
  • 81
  • 97
Nick Main
  • 1,440
  • 8
  • 15
  • Here's a closely related SO question: [How to create a lazy-seq generating, anonymous recursive function in Clojure?](http://stackoverflow.com/questions/3373157/how-to-create-a-lazy-seq-generating-anonymous-recursive-function-in-clojure). See my answer to it for a number of possible approaches. One of them is through a `letrec` macro of some sort -- see [this Gist](http://gist.github.com/486880) for my version (which works like Scheme's `letrec`). – Michał Marczyk Sep 16 '10 at 06:30
  • Thanks for all the answers. It appears that I will need full GC to handle Clojure and I'm experimenting with Gambit Scheme as the translation target. – Nick Main Sep 16 '10 at 20:12
  • You might be interested in this [stack-exchange proposal](http://area51.stackexchange.com/proposals/11464/code-review?referrer=aWNm_PdciyFqjFW8CUacGw2 "code review"). It's almost ready to begin beta, just needs a few more. – greatwolf Jan 19 '11 at 05:19

2 Answers2

14

You can create a circular reference very easily by putting some form of reference inside a data structure, then updating the reference to point back to the overall structure.

A trivial example:

(def a [(atom nil)])

(reset! (first a) a)

This will create a list with one element, which is an atom that points back at the list.

mikera
  • 105,238
  • 25
  • 256
  • 415
  • Thanks for the answer. I would only ever use a ref type as a top level object, so I never considered this. – Nick Main Sep 12 '10 at 20:36
  • is this a var that points to a list that points to an atom that references a var – Arthur Ulfeldt Sep 13 '10 at 05:30
  • 1
    @Arther - technically it is a var that points at a vector that contains an atom that points at the vector. i.e. The var itself isn't in the circular loop. – mikera Sep 13 '10 at 11:32
  • 2
    This example results in StackOverflowError in my environment:( – leo May 05 '15 at 14:40
8

In Clojure most circular data structures will explicitely go through a ref type of some kind (eg atom).

However you can create a circular sequence (it's somewhat an oxymoron):

(let [a (atom nil)] (reset! a (lazy-seq (cons 1 @a))))

And since Clojure 1.2 with deftype you can create other datatypes which can introduce circularity without using explicitely (from the usercode at least) any kind of ref type.

cgrand
  • 7,939
  • 28
  • 32