[Openmcl-devel] Thread-local bindings

Ron Garret ron at flownet.com
Fri Jun 14 20:16:31 PDT 2019


That is the correct explanation because BAR is defined in the scope of the LET that binds FOO.

On Jun 14, 2019, at 6:18 PM, martin <brooks.martin at sympatico.ca> wrote:

> Thank you Ron, Rainer and Bill
> 
> I hadn’t thought about the pervasiveness of defvar !
> Also, from CLtL2, sec 9.2: A special declaration does not affect bindings pervasively. Inner bindings of a variable implicitly shadow a special declaration and must be explicitly re-declared to be special. (However, a specialproclamation does pervasively affect bindings; this exception is made for reasons of convenience and compatibility with MacLisp.)
> 
> Let’s look at special variables.
> The following result is expected:
> 
> ? (process-run-function :process1 
>   #'(lambda ()
>       (let ((foo 4))
>         (declare (special foo)) ; NOTE
>         (flet ((bar () (print foo) :return-me-from-bar))
>           (bar)
>           (process-run-function :process2 #'bar)
>           :return-me-from-lambda))))
> 4 
> > Error: Unbound variable: FOO
> > While executing: BAR, in process PROCESS2(3).
> 
> The thread-local binding rule looks like:
> — Lambda lexically closes over code running in a newly generated thread:
> 	— except when a free variable in the new thread was dynamically scoped in the parent thread.
> 
> And … timing is everything!
> When one wraps the test expression in a function definition, then it works one way when the definition is compiled before defvar declared, and it works the other way when the definition is compiled after defvar.
> 
> Actually, I am amazed that the closed-over case works.
> In the following form, process1 terminates before process2 calls bar; nevertheless the call to bar has access to the lexical environment of process1 — or maybe that isn’t a correct description.
> 
> (process-run-function :process1 
>   #'(lambda ()
>       (let ((foo 4))
>         (flet ((bar () (print foo) :return-me-from-bar))
>           (bar)
>           (process-run-function :process2 #'(lambda () 
>                                               (sleep 10) 
>                                               (bar)
>                                               :return-me-from-lambda))))))
> 
> Martin
> 
> 
>> On Jun 14, 2019, at 12:18 PM, Ron Garret <ron at flownet.com> wrote:
>> 
>> You might want to read this:
>> 
>> http://www.flownet.com/ron/specials.pdf
>> 
>> and particularly the section called “the pervasiveness of defvar”.
>> 
>> Also: instead of running your code at the top level, try putting it inside a function and calling the function before and after the DEFVAR.  You will see the different results.  The thing that is surprising you is happening at compile time.
>> 
>> rg
>> 
>> On Jun 14, 2019, at 9:14 AM, Rainer Joswig <joswig at lisp.de> wrote:
>> 
>>> If a variable is used in a function and there is no special declaration and there is no DEFVAR, then the binding is lexical.
>>> 
>>> DEFVAR declares a variable to be special.
>>> 
>>> Then ALL new code on all levels (all lets, lambda vars, ...) will use dynamic binding.
>>> 
>>> 
>>> 
>>>> Am 14.06.2019 um 16:16 schrieb martin <brooks.martin at sympatico.ca>:
>>>> 
>>>> Hello All
>>>> 
>>>> I am confused about the semantics of thread-local bindings when using process-run-function. 
>>>> CCL version: Clozure Common Lisp Version 1.12-dev (v1.12-dev.4-3-gdd5622e9) DarwinX8664
>>>> 
>>>> Suppose that the variable foo is not globally bound:
>>>> 
>>>> ? foo
>>>> > Error: Unbound variable: FOO
>>>> 
>>>> Consider the following form:
>>>> 
>>>> (process-run-function :process1 
>>>>   #'(lambda ()
>>>>       (let ((foo 2))
>>>>         (flet ((bar () (print foo) :return-me-from-foo))
>>>>           (bar)
>>>>           (process-run-function :process2 #'bar)
>>>>           :return-me-from-lambda))))
>>>> 
>>>> The result is to print 2 twice:
>>>> 
>>>> 2 
>>>> 2 
>>>> 
>>>> Neither keyword return value appears, nor should they — I put them in the code to disambiguate printing from the value returned by print.
>>>> 
>>>> Now bind foo at top level.
>>>> 
>>>> ? (defvar foo 3)
>>>> FOO
>>>> 
>>>> Execute the form again, to get these to print results:
>>>> 
>>>> 2 
>>>> 3 
>>>> 
>>>> My confusion: 
>>>> The second result (print 2 & 3) demonstrates my understanding of thread-local bindings.
>>>> The first result (print 2 & 2) seems wrong — why didn’t Lisp complain that foo was unbound in the call to bar within :process2 ?
>>> 
>>> Because FOO uses the lexical binding introduced by the LET.
>>> 
>>>> 
>>>> My confusion gets worse — restart Lisp, so that foo is not globally bound, and do the same tests with the following form, to see it print 4 & 4.
>>>> 
>>>> (let ((foo 4))
>>>>   (process-run-function :process1 
>>>>     #'(lambda ()
>>>>         (flet ((bar () (print foo) :return-me-from-foo))
>>>>           (bar)
>>>>           (process-run-function :process2 #'bar)
>>>>           :return-me-from-lambda))))
>>>> 
>>>> 4 
>>>> 4 
>>>> 
>>> 
>>> 
>>> lexical binding
>>> 
>>> 
>>>> And now globally bind foo:
>>>> 
>>>> ? (defvar foo 5)
>>>> FOO
>>> 
>>> 
>>>> 
>>>> The form now prints 5 & 5 .
>>>> 
>>>> 5 
>>>> 5
>>>> 
>>> 
>>> dynamic binding
>>> 
>>> 
>>>> Help! What’s the rule?!?
>>>> 
>>>> Furthermore, I take it that stack-local bindings apply to variables only, not functions.
>>>> To test this, I gave bar a global definition:
>>>> 
>>>> (defun bar () (print 27))
>>>> 
>>>> But this did not change the above results; in other words, the local definition was used in both threads.
>>>> 
>>>> All consolation gratefully accepted,
>>>> Martin
>>>> 
>>>> 
>>>> 
>>>> 
>>>> 
>>>> 
>>>> _______________________________________________
>>>> Openmcl-devel mailing list
>>>> Openmcl-devel at clozure.com
>>>> https://lists.clozure.com/mailman/listinfo/openmcl-devel
>>> 
>>> _______________________________________________
>>> Openmcl-devel mailing list
>>> Openmcl-devel at clozure.com
>>> https://lists.clozure.com/mailman/listinfo/openmcl-devel
>> 
> 
> _______________________________________________
> Openmcl-devel mailing list
> Openmcl-devel at clozure.com
> https://lists.clozure.com/mailman/listinfo/openmcl-devel

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.clozure.com/pipermail/openmcl-devel/attachments/20190614/c3a616ea/attachment.htm>


More information about the Openmcl-devel mailing list