IMPORTANT: I wrote very little of this, it's mostly a culmination of the documentation provided in `fluid.h' and `NEWS' (which I assume was done by Marius Vollmer, who wrote `fluids.[ch]'). All of the verbatim text from Marius is indented, while my stuff is flush left.
Description: (from `fluids.h')
Fluids are objects of a certain type (a smob) that can hold one
SCMvalue per dynamic root. That is, modifications to this value are only visible to code that executes within the same dynamic root as the modifying code. When a new dynamic root is constructed, it inherits the values from its parent. Because each thread executes in its own dynamic root, you can use fluids for thread local storage.Each fluid is identified by a small integer. This integer is used to index a vector that holds the values of all fluids. Each root has its own vector.
Currently, you can't get rid a certain fluid if you don't use it any longer. The slot that has been allocated for it in the fluid vector will not be reused for other fluids. Therefore, only use
SCM_MAKE_FLUIDor its Scheme variantmake-fluidin initialization code that is only run once. Nevertheless, it should be possible to implement a more lightweight version of fluids on top of this basic mechanism.
NOTE: true == true value in c, false == false
value in c, #t and #f as in scheme.
true if x is a fluid
Create a new fluid object. Fluids are not special variables or some other extension to the semantics of Scheme, but rather ordinary Scheme objects. You can store them into variables (that are still lexically scoped, of course) or into any other place you like. Every fluid has a initial value of
#f.
#t if object is a fluid, else #f
scm_with_fluids
Ex (this is sorta pseudo code):
<fluid 1> = 1; <fluid 2> = 2; fluids = (<fluid 1>, <fluid 2>); vals = (3, 4); scm_swap_fluids(fluids, vals); ;; The result <fluid 1> == 3, <fluid 2> == 4, vals == (1, 2);
scm_swap_fluids, but starts swapping from
the end of each list, which is necessary to fix up a fluids list that
was passed to scm_swap_fluids, which contained the same fluid
more than once. For example:
<fluid 1> = 1; fluids = (<fluid 1>, <fluid 1>) vals = (3, 4) scm_swap_fluids(fluids, vals); <fluid 1> == 4, vals == (1, 3); [do stuff] ;; At this point, we've fiddled with <fluid 1> and now want to ;; return to our regularly scheduled value. Let's try ;; scm_swap_fluids scm_swap_fluids(fluids, vals); <fluid 1> == 3, vals == (4, 1); ;; Ack! Let's go back in time and try scm_swap_fluids_reverse scm_swap_fluids_reverse(fluids, vals); <fluid 1> == 1, vals = (3, 4); ;; Yeah!
with-fluids*. Essentially, it swaps the
fluids with the vals, sets up fluids and vals in a dynamic
wind (which understands fluids), sets the answer to the result of doing
cproc(cdata), removes them from dynamic winds, swaps
the fluids back, and returns the answer. Putting them on dynamic winds
insures that, if you leave proc, the values are put back to normal, and
if you re-enter proc, the values are swapped back to the way you want
them.
scm_with_fluids
FLUIDS is a list of fluids and VALUES a corresponding list of values for these fluids. Before THUNK gets called the values are installed in the fluids and the old values of the fluids are saved in the VALUES list. When the flow of control leaves THUNK or reenters it, the values get swapped again. You might think of this as a
safe-fluid-excursion. Note that the VALUES list is modified bywith-fluids*.
The return value is the result of thunk. The actual implementation
simply calls scm_internal_with_fluids, with cproc set to
apply_thunk (see above) and cdata set to your thunk.
The same as
with-fluids*but with a different syntax. It looks just likelet, but both FLUID and VALUE are evaluated. Remember, fluids are not special variables but ordinary objects. FLUID should evaluate to a fluid.
This is a much less confusing way to do it :)