<div dir="ltr">Dear Marc,<br><br>I ran this code:<br><div><br></div><div>(c-declare "___SCMOBJ storage;")<br><br>(define store! (c-lambda (scheme-object) void "storage = ___arg1;"))<br><br>(define get (c-lambda () scheme-object "___return(storage);"))<br><br>(define (gen-c)<br>  (let ((abc #f))<br>    (##still-copy<br>      (lambda (v)<br>         (define o v)<br>         (set! abc v)<br>         o))))<br><br>(define gen-i (eval '(lambda () (let ((abc #f))    (##still-copy (lambda (v) (define o v) (set! abc v) o))))))<br></div><div><br></div><div>To test the hypothesis that a ____STILL closure can be successfully passed as a ___SCMOBJ from Scheme to C, stay in C for a while and then be moved back to Scheme anytime.<br><br></div><div>A normal closure will not work, since it changes memory address. However, thanks to ##still-copy , I can get a closure that has a fixed memory address all up to collection, and such a closure's ___SCMOBJ can then be kept in C for as long as desired.<br></div><div><br></div><div>Also, this ___STILL closure will still be collected, so there is no memory leak problem.<br></div><div><br></div><div>The code above outputs:<br></div><div><br></div><div>> (load "test")<br>"/path/to/test.o1"<br>> (define x (gen-c)) (print x " ") (store! x) (##gc) (print (get) "\n")<br>> #<procedure #2 x> > > > #<procedure #2 x><br>> <br>(define x (gen-i)) (print x " ") (store! x) (##gc) (print (get) "\n")<br>> #<procedure #3 x> > > > #<procedure #3 x><br></div><div><br></div><div><br></div><div>The only operational requirement for the transfer of a ___SCMOBJ from C to Scheme is that the object is still alive. In the example code above, that is guaranteed by that a strong reference to the closure is kept in |x| up to that (get) has made the transfer from C to Scheme, which then produces a new strong reference to the closure, which is sufficient in itself.<br></div><div><br></div><div>Example to illustrate clean transfer of the strong reference:<br></div><div><br></div><div>(define x (gen-c)) ; Generate closure<br><br>(print x " ") <br><br>(store! x) ; Store closure in C world, however still keep strong reference in |x|<br><br>(##gc) ; All non-___STILL/___FIXED allocated objects will change ___SCMOBJ, thus invalidating them<br><br>(define y (get)) ; We pick up the ___SCMOBJ from the C world and assign it to |y|. |x| above must be maintained as a strong reference up to the completion of this step.<br><br>; |x| is no longer needed for (get) to work, here, since we have a separate strong reference to the object now, in |y|.<br><br>(set! x #f) (##gc)<br><br>; All fine.<br><br>(print y "\n")<br></div><div><br></div><div><br>The above example breaks, if the (##still-copy part is removed, in which case the closure will be ___MOVABLE, the ___SCMOBJ will be invalidated at GC, and therefore accessing the result of (get) produces SIGSEGV or similar unknown behavior, in my test it would print out #<unknown>.<br><br></div><div>Marc please confirm that what I do above here is a best practice and is all correct.<br><br>Phil<br></div></div>