From: Yossarian Yggy King
Subject: Static local variables?
Date: 
Message-ID: <1mcbedINN9ev@kiewa.cs.ubc.ca>
Hi folks,
	I was wondering if anyone out there knows a way of
declaring/using static local variables in lisp? I would like to have
variables within a function that are invisible to the enclosing forms,
but whose values are maintained across function calls.

For example, consider the (hypothetical) function:

(defun adder (x &static-local (total 0))
  (setq total (+ total x)))

Use of the function would be like

> (adder 5)
5
> (adder 10)
15
> (adder -3)
12

... any takers?

(email advice preferred, but feel free to post)

Many thanks,
Yggy
-- 
Yggy King       | Thinking the world should entertain you leads to boredom
UBC Comp Sci    | and sloth. Thinking you should entertain the world leads
Vancouver, B.C. | to bright clothes, odd graffiti and amazing grace in
Canada          | running for the bus.    -- Ann Herbert

From: Pete Halverson
Subject: Re: Static local variables?
Date: 
Message-ID: <1993Feb23.144857.6185@crd.ge.com>
In article <············@kiewa.cs.ubc.ca> ·····@cs.ubc.ca (Yossarian Yggy King) writes:
>
>	I was wondering if anyone out there knows a way of
>declaring/using static local variables in lisp? I would like to have
>variables within a function that are invisible to the enclosing forms,
>but whose values are maintained across function calls.
>
>For example, consider the (hypothetical) function:
>
>(defun adder (x &static-local (total 0))
>  (setq total (+ total x)))
>
>Use of the function would be like
>
> > (adder 5)
> 5
> > (adder 10)
> 15
> > (adder -3)
> 12

The usual way to do something like this is to use lexical closures.  Any
time a function refers to a lexical variable outside the function's scope,
you create a functional object called a "closure" which "remembers" the
binding in effect when the function is defined, even across calls to the
function, even when the original binding is no longer accessible outside
the function!

Closures are generally created with anonymous lambda functions, but it's
also possible to make named closures with DEFUN, thus

   (let ((total 0))
    (defun adder (x)
      (incf total x)))

should do what you want.
Pete Halverson                                      INET: ·········@crd.ge.com 
GE Corporate R&D Center                       UUCP: uunet!crd.ge.com!halverson
Schenectady, NY
From: Jeff Dalton
Subject: Re: Static local variables?
Date: 
Message-ID: <8466@skye.ed.ac.uk>
In article <············@pacific.cs.ubc.ca> ·····@cs.ubc.ca (Yossarian Yggy King) writes:
>
>Lexical closures are, of course, exactly what I needed.

Good.  They don't give you static locals, though.  That is,
you can't do the equivalent of declaring a local static in
a language like C, except in certain special cases.

As an example of a case that can't be handled via closures,
consider the problem of having local names for some values
that are initialized once.

In some other languages I can use static variables 

    int f()
    {
        static int initialized = FALSE;
        static int v1, v2, ...;
        if not(initialized)
        {
            v1 = ...;
            v2 = ...;
            ...;
        }
        ... procedure body code ...
    }

This is not ideal, of course.

Similar tricks can be done in Lisp (I think) by generating global
variables:

(defmacro eval-once (form)
  (let ((v (gensym)))
    `(locally (declare (special ,v))
       (if (boundp ',v)			;initialized?
           ,v
         (setq ,v ,form)))))

So instead of declaring variables static, you'd write (eval-once ...)
around forms:

  (defun f ()
    (let ((v1 (eval-once ...))
          (v2 (eval-once ...)))
      ... procedure body code ... ))

-- jd
From: Mark Friedman
Subject: Re: Static local variables?
Date: 
Message-ID: <MARKF.93Mar9155326@scoupe.harlqn.co.uk>
>>>>> On 9 Mar 93 17:02:49 GMT, ····@aiai.ed.ac.uk (Jeff Dalton) said:
 Jeff> In article <············@pacific.cs.ubc.ca> ·····@cs.ubc.ca
 Jeff> (Yossarian Yggy King) writes:
   >
   >Lexical closures are, of course, exactly what I needed.

 Jeff> Good.  They don't give you static locals, though.  That is, you
 Jeff> can't do the equivalent of declaring a local static in a
 Jeff> language like C, except in certain special cases.

 Jeff> As an example of a case that can't be handled via closures,
 Jeff> consider the problem of having local names for some values that
 Jeff> are initialized once.

 Jeff> In some other languages I can use static variables

    int f()
    {
        static int initialized = FALSE;
        static int v1, v2, ...;
        if not(initialized)
        {
            v1 = ...;
            v2 = ...;
            ...;
        }
        ... procedure body code ...
    }

Why not do:

  (let ((initialized nil)
        (v1)
        (v2))
    (defun f ()
      (when (not initialized)
         (setf v1 ...)
         (setf v2 ...)
         (setf initialized t))
      ... procedure body code ...))

Of course you could abstract this in some WITH-STATIC-VARIABLES macro.

-Mark
--
Mark Friedman
Harlequin, Inc.
One Cambridge Center
Cambridge, Ma. 02142

·····@harlequin.com
From: John W.F. McClain
Subject: Re: Static local variables?
Date: 
Message-ID: <1njaf3INN39n@senator-bedfellow.MIT.EDU>
In article <····@skye.ed.ac.uk> ····@aiai.ed.ac.uk (Jeff Dalton) writes:
>In article <············@pacific.cs.ubc.ca> ·····@cs.ubc.ca
>(Yossarian Yggy King) writes:
>>
>>Lexical closures are, of course, exactly what I needed.
>
>Good.  They don't give you static locals, though.  That is,
>you can't do the equivalent of declaring a local static in
>a language like C, except in certain special cases.
>
>As an example of a case that can't be handled via closures,
>consider the problem of having local names for some values
>that are initialized once.
>
>In some other languages I can use static variables 
>
>    int f()
>    {
>        static int initialized = FALSE;
>        static int v1, v2, ...;
>        if not(initialized)
>        {
>            v1 = ...;
>            v2 = ...;
>            ...;
>        }
>        ... procedure body code ...
>    }

I have come into this conversation late, but I think you can create
"static locals" (if I am interpreting the term correctly...) with
closures in Scheme (and I think in CL too...)

(define f
  (let ((initialized #f)
	(v1 'who-cares)
	(v2 'who-cares)
	...)
    (lambda ()
      (cond ((not initialized) (set! v1 ...)
	                       (set! v2 ...)
			       ...))
      ... procedure body code...
	  )))


John W.F. McClain
····@athena.mit.edu
From: Bill Birch
Subject: Re: Static local variables?
Date: 
Message-ID: <1993Mar11.103134.19313@uk03.bull.co.uk>
····@aiai.ed.ac.uk (Jeff Dalton) writes:

>In article <············@pacific.cs.ubc.ca> ·····@cs.ubc.ca (Yossarian Yggy King) writes:
>>
>>Lexical closures are, of course, exactly what I needed.

>As an example of a case that can't be handled via closures,
>consider the problem of having local names for some values
>that are initialized once.

>In some other languages I can use static variables 

>    int f()
>    {
>        static int initialized = FALSE;
>        static int v1, v2, ...;
>        if not(initialized)
>        {
>            v1 = ...;
>            v2 = ...;
>            ...;
>        }
>        ... procedure body code ...
>    }

Another solution is to extend the function definition
primitive. This is relatively easy when your define/defun works
by re-writing. At define-time you need to :

	*	establish the local scope of the static variables,
		just as you would for embedded defun or defines.

	*	set the initial value of the static

	*	remove the "static ...." statement from the resulting
		lambda-list

for example:

; reading static.lsp 

4353> (defun c-like-func (g)
		(static initialised nil)
		(static var 23)

		(cond ((initialised (setq var g)) 	; nonsense code
			(else var))))				; 
c-like-func

4389> c-like-func
(lambda (G12) "removed" "removed" (cond (G13 (setq G14 G12)) (else G14)))

The static statements have been replaced with "removed" since
no further evaluation is required.

In the procedure body the static variables have been replaced with 
Gensyms G13 and G14. They are not formal arguments therefore they 
behave as required.

This re-write of function definitions could probably be added 
to Scheme or Common Lisp.

Bill

PS.  A more sophisticated version would expunge the "removed" atoms.
--
 Bill Birch             	|	·······@uk03.bull.co.uk
 Bull Info. Sys. Ltd.   	|       Bull Tel: 773 4770
 Maxted Road,         		|	Bull Mail: HM14 UK03 
 Hemel Hempstead,        	|	Tel: +44 442 884770
 HERTS, HP2 7DZ, U.K.         	|	Fax: +44 442 884570
                Aviate, Navigate, Communicate...
From: Jeff Dalton
Subject: Re: Static local variables?
Date: 
Message-ID: <8467@skye.ed.ac.uk>
In article <·····················@crd.ge.com> ·········@crd.ge.com (Pete Halverson) writes:
>In article <············@kiewa.cs.ubc.ca> ·····@cs.ubc.ca (Yossarian Yggy King) writes:
>>
>>	I was wondering if anyone out there knows a way of
>>declaring/using static local variables in lisp? I would like to have
>>variables within a function that are invisible to the enclosing forms,
>>but whose values are maintained across function calls.
>>
>>For example, consider the (hypothetical) function:
>>
>>(defun adder (x &static-local (total 0))
>>  (setq total (+ total x)))

>The usual way to do something like this is to use lexical closures.  Any
>time a function refers to a lexical variable outside the function's scope,
>you create a functional object called a "closure" which "remembers" the
>binding in effect when the function is defined, even across calls to the
>function, even when the original binding is no longer accessible outside
>the function!
>
>Closures are generally created with anonymous lambda functions, but it's
>also possible to make named closures with DEFUN, thus
>
>   (let ((total 0))
>    (defun adder (x)
>      (incf total x)))
>
>should do what you want.

Note that this works only if you have control over the context and
can write a wrapper around the entire definition.  For instance,
consider

   (defun f (x)
     ...
       (static-let ((table (make-table)))
          ...)                                 
     ...)

Assume that static-let causes table to be initialized the first
time through and that it retains this value across calls.

That is, you can replace static-let using the technique above 
only if:

1. No other binding of table gets in the way, as it does in:

     (let ((table (make-table)))
       (defun f (x table)
         ...
           (let ()
              ...)
         ...)

2. You're writing the whole functin definition and so get to
   write a (let ...) around it.

If you're writing a macro that expands into a static-let,
both conditions might be violated.  (You can't tell.)

-- jd
From: 55837-larry mayka(warren)549
Subject: Re: Static local variables?
Date: 
Message-ID: <LGM.93Mar10095441@hermit.ATT.COM>
In article <····@skye.ed.ac.uk> ····@aiai.ed.ac.uk (Jeff Dalton) writes:

   Note that this works only if you have control over the context and
   can write a wrapper around the entire definition.  For instance,
   consider

      (defun f (x)
	...
	  (static-let ((table (make-table)))
	     ...)                                 
	...)

   Assume that static-let causes table to be initialized the first
   time through and that it retains this value across calls.

One can get a "static" =object= (as opposed to a static =variable=)
via LOAD-TIME-VALUE.  For example:

(defun add-to-static-table (key value)
  (let ((table (load-time-value (make-hash-table))))
    (setf (gethash key table) value)
    table))

Each call to ADD-TO-STATIC-TABLE adds a new entry to the selfsame hash
table.


        Lawrence G. Mayka
        AT&T Bell Laboratories
        ···@iexist.att.com

Standard disclaimer.