This is the mail archive of the kawa@sources.redhat.com mailing list for the Kawa project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Gargage collected top-level bindings?


This issue has come up on this mailing list in different contexts
this year, since the change was made, and I believe it will continue
to come up until top-level bindings behave the way everyone seems
to expect them to behave.

Java and Scheme programmers alike seem to expect top-level bindings to
act like Java instance variables, as if the file contents were contained
within a single Java class.  This is the way it works in essentially all
other popular JVM languages that support "top-level" bindings, including 
(among others) Nice, Rhino, Jython, JRuby, BeanShell, PNuts, and Groovy.

Put another way, people expect them to be lexically scoped to that file
(or perhaps module).  This is the way it has worked historically in the
absence of multiple threads:  you can read and write the bindings from
any function defined in the file, e.g.:

(define my-toplevel-var 10)

(define (my-function)
  (set! my-toplevel-var
	(+ 1 my-toplevel-var)))

Kawa recently changed so that the my-toplevel-var binding is not
accessible to another thread entering my-function.  That's confusing
and unintuitive.

To illustrate the problem, consider building a Swing GUI in the file.
There's no problem invoking top-level function definitions from event
handlers for the GUI widgets.  my-function as defined above could be
invoked from a mousePressed or buttonClicked handler on the Swing
thread, for instance.  But it would throw an exception when accessing
my-toplevel-var.

That's not good.

For one thing, Scheme tries to drive home the point that there's
really no difference between a variable and a function, yet top-level
bindings for functions and variables are treated differently here.

For another, there's no way to check statically for this situation
(i.e., a top-level variable being accessed by a thread other than
the one that initialized the module).  So if my-toplevel-var is only
accessed in an unusual case, e.g. an error handler, then the bug may
go undetected for arbitrarily long until that code path executes.

Even if you know about this behavior, it makes your designs awkward.
To share data between threads, you have to wrap the data in closures
using top-level functions -- assuming that even works in this case.
For small- to medium-sized scripts and modules, this is overkill.

And finally, as I mentioned before, it's not the way it works in
other languages.  So even if Kawa's current semantics for globals
are the "right thing" from some internal design perspective, it will
continue to be a source of confusion, bugs, and mailing list traffic
as long as it remains that way.

Sharing top-level bindings among threads will of course necessitate
user synchronization of those variables.  But Java programmers are
used to that, and java.util.concurrent.atomic provides some nice
wrappers to simplify the synchronization.

-steve

On 5/5/05, Per Bothner <per@bothner.com> wrote:
> Dean Ferreyra wrote:
> > I've seen this behavior when initializing and using Kawa modules from
> > Java directly, in threads that were created from Java but not with
> > (future ...).  When the thread that has initialized the module ends,
> > some binding-related thread-local objects are garbage collected, the
> > symbols are unbound, and from then on the module's global bindings give
> > the UnboundLocationException exception.
> >
> > Assuming that we're seeing the same problem, attached is my temporary
> > kludge around it.
> 
> Note that I'm not sure this is a bug in Kawa, and I'm fairly sure this
> temporary kludge is *not* The Right Thing.
> 
> Kawa "global" bindings are fluid and thread-local, so if you create a
> binding in one thread, and the thread ends goes away, then so does the
> binding.  If you have a static module, you might still be able to
> reference the ThreadLocation from a different thread, but it will be
> unbound.
> 
> Using the dynamic environment to access bidnings from a static module
> initialized by a diffferent thread is going to be tricky, and it's
> not obvious what the "right" behavior is.  If you provide some more
> details perhaps we can figure out a solution.
> --
>         --Per Bothner
> per@bothner.com   http://per.bothner.com/
>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]