Hi,
I'm new to Scheme, and new to Gambit, so I apologize if my question
is silly.
I think that the concept of wrapping a (let …) around a (lambda …) is
really neat, which got me wondering about what happens if you create
a circular reference to a lambda from the scope of the let that surrounds
it… in particular, should such a circular reference get garbage collected?
(And if so, WOW, that's a pretty clever garbage collector!)
In the following program I create 3 objects ("one", "two", and "three"), and
create wills for them. Then I destroy my references to all three objects
and call the garbage collector. The result is that 2 of the 3 objects gets
garbage collected.
My question is, is this the expected behaviour, or have I stumbled across
something more sinister?
Here's the code:
- - - CODE STARTS HERE - - -
(define (circ-obj name)
(let* ((data '(a . b) )
(func (lambda () (println "executing func for object \"" name
"\" proc: " data))))
(set-car! data func)
; (set-cdr! data fund)
; (set! data func)
func))
(define one (circ-obj 'one))
(println "CREATING ONE")
(pp one)
(one)
(println)
(define two (circ-obj 'two))
(println "CREATING TWO")
(pp two)
(two)
(println)
(define three (circ-obj 'three))
(println "CREATING THREE")
(pp three)
(three)
(println)
(println "CREATING WILLS")
(define wone (make-will one (lambda (obj) (println "killing one "
obj))))
(define wtwo (make-will two (lambda (obj) (println "killing two "
obj))))
(define wthree (make-will three (lambda (obj) (println "killing three "
obj))))
(println)
(println "DESTROYING ONE")
(set! one #f)
(##gc)
(println)
(println "DESTROYING TWO")
(set! two #f)
(##gc)
(println)
(println "DESTROYING THREE")
(set! three #f)
(##gc)
(println)
(println "Done!")
- - - CODE ENDS HERE - - -
When I run this I get the following result:
- - - SAMPLE RUN STARTS HERE - - -
CREATING ONE
(lambda () (println "executing func for object \"" name "\" proc: " data))
executing func for object "one" proc: #<procedure #2 one>b
CREATING TWO
(lambda () (println "executing func for object \"" name "\" proc: " data))
executing func for object "two" proc: #<procedure #3 two>b
CREATING THREE
(lambda () (println "executing func for object \"" name "\" proc: " data))
executing func for object "three" proc: #<procedure #4 three>b
CREATING WILLS
DESTROYING ONE
killing one #<procedure #2>
DESTROYING TWO
killing two #<procedure #3>
DESTROYING THREE
Done!
- - - SAMPLE RUN ENDS HERE - - -
Notice that the will for object "three" never gets called, which I think
means that the object hasn't been recollected by the garbage collector.
Anyway, all I'm really hoping for is an indication as to whether such
circularly referenced objects should or should not be garbage collected.
Thanks!