From: Ken Tilton
Subject: Re: closure vs global
Date: 
Message-ID: <a%e0g.14728$g24.2031@fe12.lga>
massimo wrote:
> Hi,
> 
> If I have a global:
> (defparameter *test* (function-name))

<g> I was going to ask why function-name was in parens then realized you 
meant that the way I use <>s:

(defparameter *test* <function-name>)

or sometimes I just

(defparameter *test* 'my-function)

> 
> and few other functions that use *test* to perform other operations with 
> it. I would like to make a lexical closure so i can get rid of the 
> global *test*, which is not very clean and safe option.

Why is not clean and/or safe? Anyway, I am puzzled, you are hardcoding 
other functions to look at the *test* globale to find out what function 
to call. I guess elsewhere you modify *test* during runtime? You cannot 
pass the test function as a parameter? if not, you need a global. 
Closures have nothing to do with that.
> 
> How would I define the closure and then still use test from other 
> functions? 

Like I said, you may be ascribing powers to closures they do not have. 
Or do you mean...

> How do I group multiple functions that share the same 
> variable under 1 closure??

(let ((test-function :undefined))
     (defun set-test-xxx (fn-name)
         (setf test-function fn-name))
     (defun get-test-xxx ()
         (assert (not (eq test-function :undefined)))
         test-function))

hth, ken

-- 
Cells: http://common-lisp.net/project/cells/

"Have you ever been in a relationship?"
    Attorney for Mary Winkler, confessed killer of her
    minister husband, when asked if the couple had
    marital problems.
From: Ken Tilton
Subject: Re: closure vs global
Date: 
Message-ID: <X0h0g.375$Jw2.320@fe10.lga>
massimo wrote:
> ok.
> 
> so if i have this global *test*, which is used in other functions, how 
> can i get rid of the global and use lexical variable using let??
> 
> (defparameter *test* (another-function-call))
> 
> this is your solution:
> 
> (let ((*test* (another-function-call))
>       ;; processing
>           ;; calls to other functions referencing *game*>
>         ) ;; end of let

No this was my solution:

(let ((test-function :undefined))
     (defun set-test-xxx (fn-name)
         (setf test-function fn-name))
     (defun get-test-xxx ()
         (assert (not (eq test-function :undefined)))
         test-function))

And that is wildly different from what you offered as my solution (I am 
not pissed, I just mean "this is not a quibble, you are waaaay off if 
that is how you remember what I wrote"). What you offered binds *test*, 
which is still a special variable unless you delete the defparameter, 
and i that case you should not bracket the name with asterisks. I 
created a local variable over which two functions closed.

Let's just go with my solution. Then...

> 
> 
> how would I use closure to include all functions that use *test*?
> let's say that this is one of the function that uses *test*:
> 
> (defun function-name ()
>     <do-something-with> *test*)

...this gets rewritten:

(defun function-name ()
     (<do-something-with (get-test-xxx)))

By the way, I asked but you have not answered: why is the global a 
problem? For example, you might say "I want to handle dozens of games at 
once." But if you do not answer anything, it makes it a little hard to help.

I think, btw, that we are headed for The Unspeakable Glory of Special 
Variables:

(defun process-game (game)
     (let ((*game* game))
         <various amounts of code to process the game,
           including calls to functions that reference *game*>))

Now all your functions referencign game, when visited in a /dynamic/ 
call tree, are guaranteed to be referencing the same game. You can even 
poll a socket, decide to handle a different game, and then call 
'process-game on that game instance. During that call, all functions 
will see the second game instance, and once the nested (recursive) call 
to process-game ends and the call tree working on game one resumes 
(wherever it got interrupted by the polling) all references to *game* 
will again return game one.

Yes, global variable in most languages are Evil. But CL has a way to let 
you have the benefit (not having to pass some key, prominent value all 
over the place) without the hazards/hassles.

ken