This is the mail archive of the
kawa@sources.redhat.com
mailing list for the Kawa project.
Re: Gargage collected top-level bindings?
Thanks for the explanation.
Let me step back for a second.
I started using "define-variable" as a work-around to a problem we
were having with "define" variables used with fluid-let. The attached
example shows what I was seeing.
It uses (define ...) to define a variable and a procedure in one module:
----------
(module-static #t)
(define VAR 'hello)
(define (getVAR)
VAR)
----------
and another module uses fluid-let on the variable:
----------
(define (fn)
(set! VAR 'hello)
(fluid-let ((VAR 'goodbye))
(display (format "1. VAR: ~A~%" VAR))
(display (format "2. VAR: ~A~%" (getVAR)))))
----------
With an older version of Kawa, I always get "goodbye":
----------
CLASSPATH=.:~/kawa/cvs/kawa-pure-8-31-2004-build/kawa-1.7.90.jar java ModA
1. VAR: goodbye
2. VAR: goodbye
----------
but with the latest code, the procedure call returns "hello" instead:
----------
CLASSPATH=.:~/kawa/cvs/kawa-pure-build/kawa-1.7.91.jar java ModA
1. VAR: goodbye
2. VAR: hello
----------
Which is the expected result? In the places in our code where we use
fluid-let, we expect the goodbye/goodbye behavior. Using
"define-variable" to define VAR gets me that result, but has this
UnboundLocationException issue in the presence of unrelated threads.
What do you think?
Oh, and here's how I'm compiling this:
----------
java kawa.repl --warn-undefined-variable --module-static-run -C ModB.scm
(compiling ModB.scm)
java kawa.repl --warn-undefined-variable --module-static-run --main -C
ModA.scm
(compiling ModA.scm)
----------
Dean
Per Bothner wrote:
Dean Ferreyra wrote:
I CVS updated this morning. There is one problem I've run into that
is still leading to UnboundLocationExceptions in our code around the
use of define-variable.
I can see it in my test case, too---just define VAR with
"define-variable" like so:
I don't think this is a bug.
'define-variable VAR' means "lookup VAR dynamically" - i.e. in the
per-thread dynamic environment.
Since the module is static, there is only a single "instance", and
top-level actions are only performed once. That creates bindings
in one thread.
Since the two threads aren't in an inheritance relationship, the second
thread won't and shouldn't see the definition in the first thread.
It may be possible to change define-variable so it sets the "default"
binding of VAR, rather than the current thread's. But I don't think
that would be right. The difference with (define VAR ...) is that it
declares a static binding, while define-variable explicitly says to
use dynamic lookup. Thus (define VAR ...) creates an anonymous
ThreadLocation for VAR, in that just (eval 'VAR) won't find it.
So:
(define VAR xx)
... VAR ...
gets translated to:
static public final VAR = new ThreadLocation();
static { VAR.set(xx); }
...VAR.get()...
If we do:
(define-variable VAR xx)
... VAR ...
then the latter is equivalent to:
(eval 'VAR)
though we do cache a ThreadLocation for performance.
I don't think an *unrelated* thread should be able to do (eval 'VAR).
Note I wrote "unrelated" thread. It might be useful to add a mechanism
so "related" threads could inherit from a shared Environment. But where
do we draw the line: how do we control it so that some but not all
threads share a "global" Environment? Make use of ThreadGroups?
Make use of ClassLoaders?
--- /dev/null Tue Oct 7 04:48:06 2003
+++ ModA.scm Mon May 9 19:10:46 2005
@@ -0,0 +1,11 @@
+(module-static #t)
+
+(require <ModB>)
+
+(define (fn)
+ (set! VAR 'hello)
+ (fluid-let ((VAR 'goodbye))
+ (display (format "1. VAR: ~A~%" VAR))
+ (display (format "2. VAR: ~A~%" (getVAR)))))
+
+(fn)
--- /dev/null Tue Oct 7 04:48:06 2003
+++ ModB.scm Mon May 9 19:10:54 2005
@@ -0,0 +1,6 @@
+(module-static #t)
+
+(define VAR 'hello)
+
+(define (getVAR)
+ VAR)