guile-fluid-heck


What the heck is a fluid (in Guile)

Quoting from Guile's documentation:

A "fluid"  is an object  that can store  one value per  "dynamic state".
Each thread  has a  current dynamic state,  and when accessing  a fluid,
this current dynamic state is used to provide the actual value.  In this
way, fluids can  be used for thread local storage, but  they are in fact
more flexible: dynamic  states are objects of their own  and can be made
current  for more than  one thread  at the  same time,  or only  be made
current temporarily, for example.

Fluids can also be used to simulate the desirable effects of dynamically
scoped variables.  Dynamically scoped variables are useful when you want
to set a variable to a value during some dynamic extent in the execution
of your  program and have them  revert to their original  value when the
control flow is outside of this dynamic extent.

In Guile a fluid is the infrastructure upon which SRFI-39 is built. While SRFI-39 is implemented in a separate module, and so must be loaded into Guile explicitly, fluids are always available in Guile's core.

uriel

This first half of this page is meant to be used by newbies, too.


The context sharing problem

Let's say that we have code like this:

 (define (other) 
   (something-1)) 
  
 (define (blue) 
   (something-2)) 
  
 (define (red) 
   (something-3)) 
  
 (define (that) 
   (other) 
   (blue)) 
  
 (define (this) 
   (that) 
   (red)) 
  
 (this) 

there are no arguments so everything is wonderful. Now let's say that red and blue need to access the same context:

 (define (blue ctx) 
   (something-2 ctx)) 
  
 (define (red ctx) 
   (something-3 ctx)) 

only two functions in the tree need to access ctx:

               this
              /    \
          that      red
         /    \     ~~~
    other      blue
               ~~~~

but we have to modify this and that and the call to this to let them hand the context to the inferior functions:

 (define (that ctx) 
   (other) 
   (blue ctx)) 
  
 (define (this cxt) 
   (that ctx) 
   (red ctx)) 
  
 (this ctx) 

this is the contexts sharing problem, which is one of the biggest sources of complexity in a program.

Now we ask: it there a way to let red and blue access the context without getting it from an argument?

The global variable solution

One simple solution is to put the context in a global variable, so the code becomes:

 (define (other) 
   (something-1)) 
  
 (define (blue) 
   (something-2 the-context)) 
  
 (define (red) 
   (something-3 the-context)) 
  
 (define (that) 
   (other) 
   (blue)) 
  
 (define (this) 
   (that) 
   (red)) 
  
 (define the-context ctx) 
 (this) 

beautiful: only the bodies of red and blue have to deal with the context, and they only need to know about the global symbol the-context.

But we know why this does not work well: a global variable is a mean of sharing a context in every instant of the execution of every thread in the process. This is not what we do here: we are using it to temporarily hold a value while this is evaluated.

To make this solution work: we have to add infrastructure to prevent nested function calls to store other values in the-content and to avoid concurrent access by different threads.

The fluid solution

A fluid is a generalisation of a global variable that implements the mutual exclusion and execution environment binding that solve the global variable problems, or at least most of them: it does not make a global variable a good choice in all the situations.

With a fluid in Guile the code looks like this:

 (define the-context (make-fluid)) 
  
 (define (other) 
   (something-1)) 
  
 (define (blue) 
   (something-2 (fluid-ref the-context))) 
  
 (define (red) 
   (something-3 (fluid-ref the-context))) 
  
 (define (that) 
   (other) 
   (blue)) 
  
 (define (this) 
   (that) 
   (red)) 
  
 (with-fluids ((the-context ctx)) 
   (this)) 

with-fluids stores the value ctx in the fluid bound to the-context while its body is evaluated: ctx is the value of the fluid that is "current" while (this) is evaluated.

The basic interface

There are 3 functions we have to learn: make-fluid creates a new fluid:

 (define the-context (make-fluid)) 

it takes no arguments and initialises the fluid's value to #f; fluid-ref returns the current value of the fluid:

 (fluid-ref the-context) 

fluid-set! stores a new value in the fluid:

 (fluid-set! the-context 123) 
Better interfaces

Using SRFI-16 we can make an interface with a single setter/getter function:

 (use-modules (srfi srfi-16)) 
  
 (define the-context #f) 
  
 (let* ((fld (make-fluid))) 
   (set! the-context (case-lambda 
                      ((value)   (fluid-set! fld value)) 
                      (z         (fluid-ref fld))))) 
  
 (format #t "context value: ~S~%" (the-context)) 
 (the-context 123) 
 (format #t "context value: ~S~%" (the-context)) 

which outputs:

context value: #f
context value: 123

But we can do it without extensions, too:

 (define the-context #f) 
  
 (let* ((fld (make-fluid))) 
   (set! the-context (lambda (. args) 
                       (if (null? args) 
                           (fluid-ref fld) 
                         (apply fluid-set! fld args))))) 
  
 (format #t "context value: ~S~%" (the-context)) 
 (the-context 123) 
 (format #t "context value: ~S~%" (the-context)) 
The with- macros

In Guile fluids are the infrastructure behind the with- special forms like with-output-to-string and with-input-from-file. We can have a special form for our context, too.

We build it around the dynamic-wind procedure. By wrapping a "body" thunk (a procedure with no arguments) with a dynamic-wind: we can evaluate a thunk before the body and another thunk after the body. The "before" and "after" thunks are named in-guard and out-guard. The out-guard is evaluated even if the body raises an exception.

So we can use dynamic-wind, typycally, to acquire a resource before evaluating a thunk and to release it after the evaluation. To apply this concept to a fluid we do:

 (define the-context (make-fluid)) 
  
 (let ((old-value (fluid-ref the-context))) 
   (dynamic-wind 
       (lambda () 
         (fluid-set! the-context new-value)) 
       (lambda () 
         (body-form-1) 
         (body-form-2)) 
       (lambda () 
         (fluid-set! the-context old-value)))) 

that is:

  1. save the current value of the fluid in a temporary variable;
  2. use the in-guard to store a new value in the fluid;
  3. evaluate the body forms that make use of the fluid;
  4. use the out-guard to restore the old value in the fluid.

The use of a macro allows to:

  1. avoid coding the dynamic-wind form explicitly;
  2. put the body forms directly in the with- form without enclosing them in a (lambda () ...);

this saves typing at the keyboard, prevents bugs and makes more clear what is the meaning of the code.

Using the setter/getter procedure interface the code is:

 (define the-context #f) 
  
 (let* ((fld (make-fluid))) 
   (set! the-context (lambda (. args) 
                       (if (null? args) 
                           (fluid-ref fld) 
                         (apply fluid-set! fld args))))) 
  
 (define-macro (with-the-context VALUE . FORMS) 
   `(let ((old-value (the-context))) 
      (dynamic-wind 
          (lambda () 
            (the-context ,VALUE)) 
          (lambda () 
            ,@FORMS) 
          (lambda () 
            (the-context old-value))))) 

so that:

 (with-the-context 123 
    (body-form-1) 
    (body-form-2) 
    (body-form-3)) 

is expanded to:

 (let ((old-value (the-context))) 
   (dynamic-wind 
       (lambda () 
         (the-context 123)) 
       (lambda () 
         (body-form-1) 
         (body-form-2) 
         (body-form-3)) 
       (lambda () 
         (the-context old-value)))) 

The test code:

 (the-context 123) 
 (format #t "context value: ~S~%" (the-context)) 
 (with-the-context 456 
   (format #t "context value: ~S~%" (the-context)) 
   (the-context 789) 
   (format #t "context value: ~S~%" (the-context))) 
 (format #t "context value: ~S~%" (the-context)) 

outputs:

context value: 123
context value: 456
context value: 789
context value: 123

We can nest macro invocations at will:

 (the-context 123) 
 (format #t "context value: ~S~%" (the-context)) 
 (with-the-context 456 
   (format #t "context value: ~S~%" (the-context)) 
   (with-the-context 789 
     (format #t "context value: ~S~%" (the-context)) 
     (with-the-context "abc" 
       (format #t "context value: ~S~%" (the-context))) 
     (format #t "context value: ~S~%" (the-context))) 
   (format #t "context value: ~S~%" (the-context))) 
 (format #t "context value: ~S~%" (the-context)) 

outputs:

context value: 123
context value: 456
context value: 789
context value: "abc"
context value: 789
context value: 456
context value: 123
SRFI-39

With what we have seen so far, we can easily understand how SRFI-39 is implemented in Guile. The purpose of this SRFI is to be able to parameterise a form with one or more values:

 (use-modules (srfi srfi-39)) 
  
 (define this-param (make-parameter 123)) 
 (define that-param (make-parameter "abc")) 
  
 (format #t "this ~S, that ~S~%" (this-param) (that-param)) 
 (parameterize ((this-param 456) 
                (that-param "def")) 
   (format #t "this ~S, that ~S~%" (this-param) (that-param))) 
 (format #t "this ~S, that ~S~%" (this-param) (that-param)) 

outputs:

this 123, that "abc"
this 456, that "def"
this 123, that "abc"

so it is exactly like a fluid with the setter/getter function interface.

One very useful feature of SRFI-39, and the reason why we should use it when possible, is that we can define a function to validate and convert parameter's values.

The function is invoked each time parameterize is invoked for a parameter: its only argument is the new value and its return value is stored in the parameter.

Example, doing:

 (define this-param 
   (make-parameter 123 
     (lambda (value) 
       (if (integer? value)) 
           value 
         (scm-error 'wrong-type-arg 'parameterize 
                    "wrong parameter value ~S" (list value) #f)))) 

we can raise an error if the value is not an integer.

A SRFI-39 real world example

One of the modules in GEE implements an object with a special representation for file pathnames. The maker of the object is a generic function with two methods for different arguments: symbols and strings.

 (define this-pathname (make-pathname 'path/to/file.ext)) 
 (define that-pathname (make-pathname "path/to/file.ext")) 

This module is used in the GNU Scientific Library binding to set a default directory pathname to save data files in. This is implemented with a parameter:

 (parameterize ((gsl-directory "/path/to/dir")) 
   (save #,(gvr 3 1.0 2.0 3.0) "vector.data")) 

stores the vector's elements in the file /path/to/dir/vector.data.

The parameter has the following definition:

 (define gsl-directory 
   (make-parameter #f 
     (lambda (prefix) 
       (cond 
         ((or (string? prefix) (symbol? prefix)) 
          (make-pathname prefix)) 
         (else 
          (assert-pathname/or-false prefix 'parameterize) 
          prefix))))) 

so:

  1. if prefix is a symbol or a string, a new pathname object is made and stored in the parameter;
  2. else prefix is validated as pathname object or #f: if it is not, an error is raised; else it is stored in the parameter.

It follows that the following three forms are acceptable:

 (parameterize ((gsl-directory '/path/to/dir)) 
   ...) 
  
 (parameterize ((gsl-directory "/path/to/dir")) 
   ...) 
  
 (define p (make-pathname "/path/to/dir")) 
 (parameterize ((gsl-directory p)) 
   ...) 

So what is a fluid?

Let's not worry about how a fluid is really implemented, let's try to build a how-it-works model. A fluid is a 4-tuple of values:

  1. a tree, shared among all the threads;
  2. a map, shared among all the threads;
  3. a set, shared among all the threads;
  4. a thread-specific value.

The choice to use a tree is not fully correct, but let's try it anyway.

Fluid in a single thread process

In normal usage (more on this later) within a single thread process the tree is simplified to a linked list handled like a stack; this code:

 (define context (make-fluid)) 
  
 (define (log) 
   (format #t "context: ~A~%" (fluid-ref context))) 
  
 ;; ---------------------------------------- checkpoint 0 
 (log) 
 (with-fluids ((context 1)) 
   ;; -------------------------------------- checkpoint 1 
   (log) 
   (with-fluids ((context 2)) 
     ;; ------------------------------------ checkpoint 2 
     (log) 
     (with-fluids ((context 3)) 
       ;; ---------------------------------- checkpoint 3 
       (log) 
       (fluid-set! context 4) 
       ;; ---------------------------------- checkpoint 4 
       (log)) 
     ;; ------------------------------------ checkpoint 5 
     (log)) 
   ;; -------------------------------------- checkpoint 6 
   (log)) 
 ;; ---------------------------------------- checkpoint 7 
 (log) 

prints:

context: #f
context: 1
context: 2
context: 3
context: 4
context: 2
context: 1
context: #f

so we see that:

this handling of the fluid is possible because Guile has the dynamic-wind form: no dynamic-wind, no fluids.


The tree grows like this:

checkpoint 0  | checkpoint 1  | checkpoint 2  | checkpoint 3
              |               |               |
 ------       |  ------       |  ------       |  ------
| root |-> #f | | root |-> #f | | root |-> #f | | root |-> #f
 ------       |  ------       |  ------       |  ------
              |    |          |    |          |    |
              |  ------       |  ------       |  ------
              | | nod1 |-> 1  | | nod1 |-> 1  | | nod1 |-> 1
              |  ------       |  ------       |  ------
              |               |    |          |    |
              |               |  ------       |  ------
              |               | | nod2 |-> 2  | | nod2 |-> 2
              |               |  ------       |  ------
              |               |               |    |
              |               |               |  ------
              |               |               | | nod3 |-> 3
              |               |               |  ------
--------------+---------------+---------------+---------------
checkpoint 4  | checkpoint 5  | checkpoint 6  | checkpoint 7
              |               |               |
 ------       |  ------       |  ------       |  ------
| root |-> #f | | root |-> #f | | root |-> #f | | root |-> #f
 ------       |  ------       |  ------       |  ------
   |          |    |          |    |          |
 ------       |  ------       |  ------       |
| nod1 |-> 1  | | nod1 |-> 1  | | nod1 |-> 1  |
 ------       |  ------       |  ------       |
   |          |    |          |               |
 ------       |  ------       |               |
| nod2 |-> 2  | | nod2 |-> 2  |               |
 ------       |  ------       |               |
   |          |               |               |
 ------       |               |               |
| nod3 |-> 4  |               |               |
 ------       |               |               |

The map is used to keep track of which node is current: it maps a thread-associated identifier to a reference to the current node; if we represent the map as an assoc list we can plot it like this:

checkpoint 0    | checkpoint 1    | checkpoint 2    |
                |                 |                 |
((thd0 . root)) | ((thd0 . nod1)) | ((thd0 . nod2)) |
----------------+-----------------+-----------------+
checkpoint 3    | checkpoint 4    | checkpoint 5    |
                |                 |                 |
((thd0 . nod3)) | ((thd0 . nod3)) | ((thd0 . nod2)) |
----------------+-----------------+-----------------+
checkpoint 6    | checkpoint 7    |
                |                 |
((thd0 . nod1)) | ((thd0 . nod1)) |

The set and the value just hold the thread-associated identifier.

Fluid in a multiple thread process

When a new thread is created: a new branch in the fluid's tree is opened, with a node holding the same value of the father. If before thread creation the tree looks like this:

 ------
| root |-> #f
 ------
   |
 ------
| nod1 |-> 1
 ------

after the thread creation it looks like this:

 thread 0     |  thread 1
              |
 ------       |
| root |-> #f |
 ------       |
   |          |
 ------       |
| nod1 |-> 1  |
 ------       |
   |          |   ------
   +-------------| nod2 |-> 1
              |   ------

and the map between threads and nodes is:

((thd0 . nod1)
 (thd1 . nod2))

Now the two threads can go on adding nested levels independently:

 thread 0     |  thread 1
              |
 ------       |
| root |-> #f |
 ------       |
   |          |
 ------       |
| nod1 |-> 1  |
 ------       |
   |          |   ------
   +-------------| nod2 |-> 1
   |          |   ------
 ------       |     | 
| nod3 |-> 2  |   ------
 ------       |  | nod4 |-> 3
              |   ------

and the map between threads and nodes becomes:

((thd0 . nod3)
 (thd1 . nod4))

The set holds the two threads identifiers (thd0 thd1); the thread specific data for thread 0 holds thd0 and the thread specific data for thread 1 holds thd1.

Thread branch rewinding

When thread 0 "rewinds its fluid" branch: it goes up to nod1 and then root. When thread 1 rewinds its fluid branch: it can go only up to nod2, which is its root. So it is more correct to look at thread creation as a new stack creation:

 thread 0     | thread 1
              |
 ------       |  ------
| root |-> #f | | nod2 |-> 1
 ------       |  ------
   |          |
 ------       |
| nod1 |-> 1  |
 ------       |

and then the two stacks evolve independently:

 thread 0     | thread 1
              |
 ------       |  ------
| root |-> #f | | nod2 |-> 1
 ------       |  ------
   |          |     |
 ------       |  ------
| nod1 |-> 1  | | nod4 |-> 3
 ------       |  ------
   |          |
 ------       |
| nod3 |-> 2  |
 ------       |
Multi threading tests

We can test the described behaviour with the following script.

 (use-modules (ice-9 threads)) 
  
 (define *context* (make-fluid)) 
  
 (define (log thd) 
   (format #t "thread ~A, context: ~A~%" 
           thd (fluid-ref *context*))) 
  
 (log 0) 
 (with-fluids ((*context* 1)) 
   (log 0) 
   (begin-thread (log 1) 
                 (with-fluids ((*context* 3)) 
                   (log 1)) 
                 (log 1)) 
   (with-fluids ((*context* 2)) 
     (log 0)) 
   (log 0)) 
 (log 0) 

the output is:

thread 0, context: #f
thread 0, context: 1
thread 0, context: 2
thread 0, context: 1
thread 0, context: #f
thread 1, context: 1
thread 1, context: 3
thread 1, context: 1

What if we first create the thread and then the fluid? We use the following script; to make thread 1 wait for thread 0 to make the fluid we use a condition variable:

 (use-modules (ice-9 threads)) 
  
 ;; -------------------------------------------------- 
  
 (define mux (make-mutex)) 
 (define var (make-condition-variable)) 
  
 (define (wait-other) 
   (dynamic-wind 
       (lambda () (lock-mutex mux)) 
       (lambda () (wait-condition-variable var mux)) 
       (lambda () (unlock-mutex mux)))) 
  
 (define (wake-up-other) 
   (dynamic-wind 
       (lambda () (lock-mutex mux)) 
       (lambda () (signal-condition-variable var)) 
       (lambda () (unlock-mutex mux)))) 
  
 ;; -------------------------------------------------- 
  
 (define *context* #f) 
  
 (define (log thd) 
   (format #t "thread ~A, context: ~A~%" 
           thd (fluid-ref *context*))) 
  
 (begin-thread 
  (wait-other) 
  (log 1) 
  (with-fluids ((*context* 3)) 
    (log 1)) 
  (log 1)) 
  
 (set! *context* (make-fluid)) 
 (fluid-set! *context* 0) 
 (with-fluids ((*context* 1)) 
   (usleep 40000) 
   (wake-up-other) 
   (log 0) 
   (with-fluids ((*context* 2)) 
     (log 0)) 
   (log 0)) 

the output is:

thread 0, context: 1
thread 0, context: 2
thread 0, context: 1
thread 1, context: #f
thread 1, context: 3
thread 1, context: #f

so it works but the new thread gets #f as root value, not a value from the branch of thread 0.

Fluid in a single thread process with multiple environments

We have seen that thread creation make a branch in a fluid's tree; this happens because a thread is a "fluid's dynamic state". Every time a new dynamic state is created, a branch is opened in all the fluids.

Guile lets us make dynamic states at will, and activate them with the with-dynamic-state procedure:

 (define *context* (make-fluid)) 
 (define dys1 #f) 
  
 (define (log) 
   (format #t "dynamic state ~A, context: ~A~%" 
           (current-dynamic-state) (fluid-ref *context*))) 
  
 (log) 
 (with-fluids ((*context* 1)) 
   (log) 
  
   (set! dys1 (make-dynamic-state)) 
   (with-dynamic-state dys1 
     (lambda () 
       (log) 
       (with-fluids ((*context* 3)) 
         (log)) 
       (log))) 
  
   (with-fluids ((*context* 2)) 
     (log)) 
   (log)) 
 (log) 

the output is:

dynamic state #<dynamic-state 804b1c0>, context: #f
dynamic state #<dynamic-state 804b1c0>, context: 1
dynamic state #<dynamic-state 40348670>, context: 1
dynamic state #<dynamic-state 40348670>, context: 3
dynamic state #<dynamic-state 40348670>, context: 1
dynamic state #<dynamic-state 804b1c0>, context: 2
dynamic state #<dynamic-state 804b1c0>, context: 1
dynamic state #<dynamic-state 804b1c0>, context: #f

exactly what happens with multiple threads.


When a new dynamic state is made: the map holds the thread's identifier and the new dynamic state identifier:

((thd0 . nod1)
 (dys1 . nod2))

the set holds the identifiers (thd0 dys1).

The thread specific data holds thd0 first, then while with-dynamic-state is evaluated, it holds dys1; and finally it holds thd0 again.

The set holds all the dynamic states and the thread specific data holds the dynamic state that is current for that thread.

Fluid in a multi thread process with multiple environments

We now demonstrate that a dynamic state built with make-dynamic-state is shared among threads. The script:

 (define *context* (make-fluid)) 
 (define dys1 #f) 
  
 (define (log thd) 
   (format #t "thread ~S, dynamic state ~A, context: ~A~%" 
           thd (current-dynamic-state) (fluid-ref *context*))) 
  
 (log 0) 
 (with-fluids ((*context* 1)) 
   (log 0) 
  
   (set! dys1 (make-dynamic-state)) 
   (with-dynamic-state dys1 
     (lambda () 
       (log 0) 
       (with-fluids ((*context* 3)) 
         (log 0)) 
       (log 0))) 
  
   (with-fluids ((*context* 2)) 
     (log 0)) 
   (log 0)) 
  
 (begin-thread (log 1) 
               (with-fluids ((*context* 3)) 
                 (log 1) 
                 (with-dynamic-state dys1 
                   (lambda () 
                     (log 1)))) 
               (log 1)) 

outputs:

thread 0, dynamic state #<dynamic-state 804b1c0>, context: #f
thread 0, dynamic state #<dynamic-state 804b1c0>, context: 1
thread 0, dynamic state #<dynamic-state 4035ed30>, context: 1
thread 0, dynamic state #<dynamic-state 4035ed30>, context: 3
thread 0, dynamic state #<dynamic-state 4035ed30>, context: 1
thread 0, dynamic state #<dynamic-state 804b1c0>, context: 2
thread 0, dynamic state #<dynamic-state 804b1c0>, context: 1
thread 1, dynamic state #<dynamic-state 403b6810>, context: #f
thread 1, dynamic state #<dynamic-state 403b6810>, context: 3
thread 1, dynamic state #<dynamic-state 4035ed30>, context: 1
thread 1, dynamic state #<dynamic-state 403b6810>, context: 3
thread 1, dynamic state #<dynamic-state 403b6810>, context: #f

we see that the dynamic state #<dynamic-state 4035ed30> when activated from thread 1 has, in the fluid, the last value left by thread 0.


Now a weird test: can a thread's dynamic state be shared among threads? The script:

 (define *context* (make-fluid)) 
 (define thread-0-dys (current-dynamic-state)) 
  
 (define (log thd) 
   (format #t "thread ~S, dynamic state ~A, context: ~A~%" 
           thd (current-dynamic-state) (fluid-ref *context*))) 
  
 (log 0) 
 (with-fluids ((*context* 1)) 
   (log 0) 
   (begin-thread (log 1) 
                 (with-fluids ((*context* 3)) 
                   (log 1) 
                   (with-dynamic-state thread-0-dys 
                     (lambda () 
                       (log 1))) 
                   (log 1)) 
                 (log 1)) 
   (sleep 1) 
   (log 0)) 
 (log 0) 

outputs:

thread 0, dynamic state #<dynamic-state 804b1c0>, context: #f
thread 0, dynamic state #<dynamic-state 804b1c0>, context: 1
thread 1, dynamic state #<dynamic-state 403b6810>, context: 1
thread 1, dynamic state #<dynamic-state 403b6810>, context: 3
thread 1, dynamic state #<dynamic-state 804b1c0>, context: 1
thread 1, dynamic state #<dynamic-state 403b6810>, context: 3
thread 1, dynamic state #<dynamic-state 403b6810>, context: 1
thread 0, dynamic state #<dynamic-state 804b1c0>, context: 1
thread 0, dynamic state #<dynamic-state 804b1c0>, context: #f

we see that:

  1. the dynamic state of thread 0 is #<dynamic-state 804b1c0>;
  2. when thread 1 is run it gets the current value from the last node of thread 0 (that is 1), fine;
  3. thread 1 sets the fluid to 3, fine;
  4. when thread 1 activates the dynamic state of thread 0: it gets from the fluid the last value left by thread 0 (that is 1).

So it works!

Conclusions

Guile's fluids are a high level and powerful abstraction tool that deserves to be learned; they make the code slower but can save time in data structures design.

Dynamic states different than threads are usually not needed, but an interesting idea to explore is to associate dynamic states usage with event driven programming.

Remember to use fluids with moderation, if you get the fluiditics illness messy code will result.


category-guile