[Openmcl-devel] [CLSQL] Slime, CLSQL, and reader macros

Gary Byers gb at clozure.com
Mon Apr 5 10:41:42 PDT 2010

On Fri, 2 Apr 2010, Patrick May wrote:

> On Apr 2, 2010, at 1:20 PM, Patrick May wrote:
>> On Apr 1, 2010, at 2:10 PM, Helmut Eller wrote:
>>> * Patrick May [2010-04-01 19:59+0200] writes:
>>>> 	Interesting.  I tried this with SBCL and it worked.  Why would
>>>> 	ccl64 behave differently?  (Code below.)
>>> Probably because *readtable* is a only modified in the per-thread
>>> binding in CCL and if you only change it in the repl thread other
>>> threads don't see that.
> 	Now that Helmut has identified the issue I'm having with using CLSQL in Slime with CCL, can anyone tell me if it is possible to configure CCL so that the readtable is shared across threads?

I have a feeling that this answer will be longer than you want  ...

? (dotimes (i 3)
   (let* ((thread-number i))
         (format nil "example~d" i)
         (lambda () (format t "~&this is thread ~d, and the value of *READTABLE* is ~s" thread-number *readtable*)))))
this is thread 0, and the value of *READTABLE* is #<READTABLE #x302000315ADD>
this is thread 1, and the value of *READTABLE* is #<READTABLE #x302000315ADD>
this is thread 2, and the value of *READTABLE* is #<READTABLE #x302000315ADD>

We didn't do anything ... er, special ... there, and all threads "see" the
same value of *READTABLE*.  What Helmut noted is that the binding of *READTABLE*
is thread-specific in CCL; thread-specific bindings may or may not involve the
same values.

Suppose we had a slightly different example (that I'm too lazy to
write ...) where one thread repeatedly called READ (and therefore
referenced *READTABLE*) and another thread (just for the sake of
argument) repeatedly slept for random intervals and did something like

(setq *readtable* *special-readtable-for-parsing-C-code*)

whenever it woke up.  If the two threads shared the same -binding- of
*READTABLE*, then the SETQ in the second thread would affect the value
of that variable visible in the first thread, and the consequences of
that would probably be unpleasant.

A binding of a special variable can be "dynamic" or "static"; a
dynamic binding is one established by
LET/LET*/LAMBDA/PROGV/whatever-else-i'm-forgetting.  A reference to or
assignment to a special variable that's made outside the extent of any
dynamic binding of that variable could be said to be "static"; a toplevel
assignment via DEFVAR or DEFPARAMETER usually affects the static binding
of that variable.  Static bindings are potentially visible to all threads;
dynamic bindings are inherently thread-private.

Helmut's observation refers to the fact that CCL threads ordinarily
start up with dynamic bindings of a few dozen special variables
(including *readtable*) in effect; Jon Anthony noted that this set
can be extended via the :INITIAL-BINDINGS argument to PROCESS-RUN-FUNCTION.
The good news is that these mechanism help to guard against inadvertent
cross-thread side-effects and provide some control over the initial values
of thread-specific bindings; the bad news is that the :INITIAL-BINDINGS
mechanism is only applicable to threads that you create.

SLIME apparently executes some code directly in its REPL thread and other
code in newly-created, typically-short-lived threads.  The dynamic environment
in which code is executed in these threads may differ significantly from
the environment in effect in the REPL thread.  There may be ways of making
it more similar (by specifying additional bindings and values to be put
into effect when these short-lived threads start up), and there might be
ways of persuading SLIME not the "communication style" in which some
forms are executed in separate threads.

If these mechanisms don't exist or aren't satisfactory, there are CCL-specific
ways of controlling the values to which special variables are bound in newly-
created threads.  That seems like kind of a heavy hammer to use in order to
gain control over how things are bound in threads you didn't explicitly ask
to, but you could do something like:

(ccl:def-standard-initial-binding *readtable* *readtable-with-clsql-support*)

That's a macro, and it's intended to be used "declaratively" (sort of
like DEFVAR/DEFPARAMETER).  It's not (AFAIK) documented, but it is
exported and its syntax and at least most aspects of its semantics are
unlikely to change.  (Those semantics - such as they are - are that
subsequently-created threads will execute with *READTABLE* bound dynamicallly 
to what I'm calling *READTABLE-WITH-CLSQL-SUPPORT*.  Whether or not it
magically causes existing threads (including the calling thread) to establish
a dynamic binding in some magic/funky way is unspecified; it doesn't currently
do so, but there are reasons to think that it should.)

> Thanks,
> Patrick

More information about the Openmcl-devel mailing list