[Contents]   [Back]   [Prev]   [Up]   [Next]   [Forward]  


fluid

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 SCM value 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_FLUID or its Scheme variant make-fluid in 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.

C Macro: SCM_FLUIDP (x)
true if x is a fluid

C Macro: SCM_FLUID_NUM (x)
The fluid number of x.

C Macro: SCM_FAST_FLUID_REF (n)
A very quick way to get at the value associated with the fluid n (where n is the number of the fluid, not the actual fluid object). It doesn't do any error checking, so be sure that the fluid is defined in the current dynamic root.

C Macro: SCM_FAST_FLUID_SET_X (n, val)
A quick way to set the value associated with fluid number n in the current dynamic root. Again, be careful, or you could end up hosing yourself.

Function: make-fluid
C Function: SCM scm_make_fluid (void)

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.

Function: fluid? object
C Function: SCM scm_fluid_p (SCM object)
#t if object is a fluid, else #f

Function: fluid-ref fluid
C Function: SCM scm_fluid_ref (SCM fluid)
Gets the value associated with fluid in the current dynamic root.

Function: fluid-set! fluid val
C Function: SCM scm_fluid_set_x (SCM fluid, SCM val)
Sets the value of fluid in the current dynamic root. Returns val.

Internal C Function: void scm_swap_fluids (SCM fluids, SCM vals)
fluids and vals are both lists of, well, fluids and values. For each fluid in fluids, we swap it's current value with the corresponding element of val. This is basically a utility function for 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);

Internal C Function: void scm_swap_fluids_reverse (SCM fluids, SCM vals)
Does the same thing as 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!

Internal C Function: SCM scm_internal_with_fluids (SCM fluids, SCM vals, SCM (*cproc)(), void *cdata)
The is the meat of 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.

Internal C Function: static SCM apply_thunk (void *thunk)
Simply returns the value of applying thunk with no arguments. Used in scm_with_fluids
Function: with-fluids* fluids values thunk
C Function: SCM scm_with_fluids (SCM fluids, SCM vals, SCM thunk)

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 by with-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.

Macro: with-fluids ((FLUID VALUE) ...) FORM ...

The same as with-fluids* but with a different syntax. It looks just like let, 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 :)


[Contents]   [Back]   [Prev]   [Up]   [Next]   [Forward]