This page is part of the web mail archives of SRFI 15 from before July 7th, 2015. The new archives for SRFI 15 contain all messages, not just those from before July 7th, 2015.
From: Per Bothner <per@xxxxxxxxxxx> Date: 15 Nov 1999 23:13:21 -0800 > I would like to argue against any DYNAMIC-WIND + SET! sort of > "fluid variable" system. The problem is threads. If you have a > thread model, then any thread switch involves unwinding up the > stack to the common ancestor continuation, then winding down into > the activated continuation. This seems unacceptably expensive; thread > switch should be a low-overhead operation. (Let us not confuse specification with implementation. When I was (briefly) involved with C++ standardization, I learned the "as-if rule." This refers to the fact that a feature may be defined "as if" it were implemented in a particular way, but an implementation is free to use a different implementation as long as long as no well-defined program can tell the difference.) It's not a question of *confusing* implementation & spec. It's an issue of the *interaction* between implementation & spec -- can the spec be provided in important general classes of Scheme implementations? A more fundamental problem with the fluid-let specification is that it does not support a thread model that may have true parallel threads. When the topic of "thread local variables" came up in the Guile mailing list (see http://sourceware.cygnus.com/ml/guile/1999-03/) I proposed a "deep binding" model of variable access (see http://sourceware.cygnus.com/ml/guile/1999-03/msg00023.html): Each thread has an association list of fluid bindings. When fluid-let is evaluated, it conses up a new association to the front of the list. That becomes the current fluid binding association list while the body of the fluid-let is evaluated. The old list is restored when the fluid-let finishes. (This can be implemented with the appropriate dynamic-wind.) When a new thread is created, it initializes its fluid binding list with the *current* list from the parent thread. Thus all bindings are initially shared. When a non-local variable is evaluated, the evaluator searches the current thread's fluid binding list, and finds the first binding for the given name. If none, is found, the global binding is returned. When a set! is evaluated, it also searches the fluid bindigs list of the current thread, and modifies the first association whose name matches. If there is none, the global binding is modified. This is of course only the semantic model; an actual implementation may use caching or other thread-local storage. Actually, that's a fairly operationally defined "semantics" -- but nonetheless, you are proposing what Gambit has, and it's pretty close to what I have proposed (what Scheme 48 has). The important point is handling the interaction between threads and dynamic binding. This model that you, Brad, and I are pushing allows threads to share and not share dynamic scope, as appropriate, just as you said in your msg: This model is actually very general; it allows rather fine-grained control over which variables are shared between which threads, but using a very simple but general mechanism. (As such I think it first very much in the spirit of Scheme.) And it's in Kawa, Scheme 48, and Gambit, at least. The distinction between what Gambit has and what Scheme 48 has is that S48 builds the mechanism on top of a new data type, the "fluid cell." You have to get your hands on one of these values through the general mechanisms in the program for passing around data, to reference a dynamically-bound value. This can be viewed as a sort of lexical or data-flow level of control on this mechanism. Gambit's dynamic vars allow anyone who can *write down the name* of a dynamic var to access its dynamically bound value. I would argue that's too uncontrolled. Also, you have to introduce a whole new linguistic mechanism, whereas fluid cells just require some new primitive procedures, with no actual language-level hacking. In practice, this is probably a small point. We are all reading off the same page. Lars has made the response that he's not trying to use this SRFI to come up with a "standard" for dynamic binding; he's just trying to codify existing practice: From: Lars Thomas Hansen <lth@xxxxxxxxxxx> All of these objections are reasonable, but they do not speak to the purpose of this particular SRFI. The purpose of the SRFI is only to codify an already existing practice that has slight variations across implementations (namely, some protect the bindings with DYNAMIC-WIND and some don't). I submitted it because I find myself using FLUID-LET in some of my programs, because it is a convenient mechanism for temporarily and reliably overriding the values of global variables. This seems like a waste of a SRFI to me. There's not too much to say about dynamic scoping. The only real issue is their interaction with threads, and there's basically one answer to how to handle that. The distinctions between Gambit's, Kawa's and S48's dynamic-scope stuff are minor. Casting a non-thread-safe mechanism into stone with a SRFI when one could have gone that one extra step is stopping short. (More generally, I do not think that the SRFI process is useful only for designing new stuff; it is useful also for collecting old stuff that is known to be useful, even in limited contexts.) In that case, we could take every incompatible R5RS extension of every Scheme implementation out there and make it a SRFI? Doesn't seem like a good thing to me. I'd rather use the SRFI process to get people to come to as wide a consensus as possible on the Right Thing, so that the SRFI record becomes a growing spec of agreed-upon design. (I bear in mind that complete agreement is never possible -- just about everyone (including me) can find something in SRFI-1 they don't like, for example.) But in the end, it's Lars' SRFI. Perhaps at minimum Lars could add some text explaining to readers of the SRFI that this mechanism has problems interacting with threads and that if they do not have backwards-compatibility issues, they should avoid using it in favor of better dynamic-scope mechanisms defined in presumed-later SRFIs? -Olin