On Fri, 2021-12-31 at 10:09 +0100, Chun Tian wrote:
Hi,
Imagine the following simple "algorithm" (or strategy): "shadowed values always have priority, otherwise the current value of global variables are used."
That's called rebinding a special variable.
Problem is that, how could the lambda function know it was called with a shadowed value?
The whole point of special variables is to make it oblivious whether one is using the global binding or a thread-local binding, so code shouldn't be aware of that in general.
An easy way is to use another global variable which should be never changed by SETQ:
So consider the following modified examples:
(defvar *foo* "original value") (defvar *shadowed* nil)
(defun create-server (&optional (port 1965)) (usocket:socket-server "0.0.0.0" port (let ((foo *foo*) (shadowed *shadowed*)) (lambda (stream) (let ((v (if shadowed foo *foo*))) (write v :stream stream)))) () :multi-threading t :element-type 'character :in-new-thread t))
Yes, you can do something like that but it's a dubious use of special variables and likely prone to bugs. For the stated use of allowing a global binding during production use and injecting other values during testing, the code I showed works fine.
But note that, in general, if you change the value of a global variable from one thread, the change may not be immediately visible from another thread, unless you use something like locks (or atomic updates) from multi-threading libraries.
For interactive development, the change is practically immediate. When they warn that writes take time to propagate to other cores, we're talking about perhaps hundreds of usec instead of the usual <1usec, not smething that is humanly visible.