common-lispsetf

What happens when I use a plain setf statement in LISP?


I know that when you want to make a dynamic/global binding in Lisp, you use either defparameter or defvar. I also know that you can make lexical bindings, well, almost everywhere, using defun argument lists or let statements.

What I'm wondering is what exactly it is I make when I make a statement like this where x was not declared or used anywhere else in the code:

(setf x 10 )

This appears to work fine, and x doesn't seem to behave like a lexical variable. Is it actually a dynamic global, the same as if I'd used defparameter or defvar, or is it something else entirely?


Solution

  • What it actually does is unspecified in the ANSI Common Lisp standard.

    Generally I prefer any CL implementation to just set the dynamically bound value or global value. It should not to do anything else. CMUCL by default seemed to think that it was a good idea to declare the symbol special then. But that was a bad idea, since there was no obvious way to get rid of a global special declaration.

    So, typically I would expect something like this (here, LispWorks):

    CL-USER 66 > (defun foo () (setf x44 10))
    FOO
    

    The global variable is still unbound:

    CL-USER 67 > x44
    
    Error: The variable X44 is unbound.
      1 (continue) Try evaluating X44 again.
      2 Specify a value to use this time instead of evaluating X44.
      3 Specify a value to set X44 to.
      4 (abort) Return to level 0.
      5 Return to top loop level 0.
    
    Type :b for backtrace or :c <option number> to proceed.
    Type :bug-form "<subject>" for a bug report template or :? for other options.
    
    CL-USER 68 : 1 > :top
    

    Let's call the function:

    CL-USER 69 > (foo)
    10
    

    Now it has a global value:

    CL-USER 70 > x44
    10
    

    But the variable is not declared to be special (as it would be by DEFVAR or DEFPARAMETER). Here a lexical binding is established.

    CL-USER 71 > (let ((x44 20)) (foo) x44)
    20
    

    When we declare the local variable to be special, then our function changes the binding:

    CL-USER 72 > (let ((x44 20)) (declare (special x44)) (foo) x44)
    10