3
votes

I have a question concerning the relation between symbols and global variables.

The hyperspec states for the value attribute of a symbol:

"If a symbol has a value attribute, it is said to be bound, and that fact can be detected by the function boundp. The object contained in the value cell of a bound symbol is the value of the global variable named by that symbol, and can be accessed by the function symbol-value."

If I apply the following steps:

CL-USER> (intern "*X*")
*X*
NIL
CL-USER> (boundp '*x*)
NIL
CL-USER> (setf (symbol-value '*x*) 1)
1
CL-USER> (boundp '*x*)
T

as I understand the above cited conditions are fulfilled. There should be a global variable named by the symbol and the value of the variable is the symbol-value. But this is wrong.

CL-USER> (describe '*x*)
COMMON-LISP-USER::*X*
  [symbol]

*X* names an undefined variable:
  Value: 1
; No value
CL-USER> 

It has to be proclaimed special.

CL-USER> (proclaim '(special *x*))
; No value
CL-USER> (describe '*x*)
COMMON-LISP-USER::*X*
  [symbol]

*X* names a special variable:
  Value: 1
; No value
CL-USER> 

Can you please explain this behaviour. What means an "undefined variable", I did not find this term in the hyperspec.

(I use SBCL 1.3.15.)

Thank you for your answers.

Edit:

(Since this comment applies to both answers below (user Svante and coredump), I write it as an Edit and not as a comment to both answers).

I agree with the answers that * x* is a global variable.

The hyperspec states for global variable:

"global variable n. a dynamic variable or a constant variable."

Therefore I think now, the reason why SBCL says it is "undefined" is not whether is special, but whether it is a dynamic (special) variable or a constant variable (hyperspec:"constant variable n. a variable, the value of which can never change").

The third definition which is mentioned in the below answers (maybe I understand the answers wrong), that it is a global variable which is not special (and not a constant) does not exist according to the hyperspec.

Can you agree with that?

Edit 2:

Ok, in summary, I thought, since the hyperspec does not define undefined global variables, they do not exist.

But the correct answer is, they do exist and are undefined, that means it is implementation dependent how it is dealt with them.

Thank you for your answers, I accept all three of them, but I can only mark one.

3

3 Answers

4
votes

There is a global variable named by the symbol, and its value is the symbol-value. That is what the output tells you. The thing that is undefined is the status of the variable: whether it is special. I agree that the wording of the output is a bit special.

If you set the value of a variable without creating it first (which is what a naked setq would do as well), it is undefined whether it becomes special or not.

Conventionally, one does not use global variables that are not special. That's why you should use defvar, defparameter etc..

4
votes

As said in the other answer(s), *X* is not declare special (dynamic). SBCL also gives you a warning if your lexically bind the symbol:

FUN> (let ((*X* 30)) (list *X* (symbol-value '*X*)))
; in: LET ((*X* 30))
;     (LET ((FUN::*X* 30))
;       (LIST FUN::*X* (SYMBOL-VALUE 'FUN::*X*)))
; 
; caught STYLE-WARNING:
;   using the lexical binding of the symbol (FUN::*X*), not the
;   dynamic binding, even though the name follows
;   the usual naming convention (names like *FOO*) for special variables
; 
; compilation unit finished
;   caught 1 STYLE-WARNING condition
(30 10)

Note also what happens if *X* is locally declared as special:

FUN> (let ((*X* 30)) (declare (special *X*)) (list *X* (symbol-value '*X*)))
(30 30)

The symbol-value accessor retrieves the binding from the dynamic environment.

3
votes

global variable which is not special (and not a constant) does not exist according to the hyperspec.

The actual behaviour is undefined in the standard, but in implementations it might work in some way.

This example in LispWorks:

CL-USER 46 > (boundp 'foo)
NIL

So FOO is unbound.

CL-USER 47 > (defun baz (bar) (* foo bar)) 
BAZ

The above defines a function baz in the LispWorks interpreter - it is not compiled. There is no warning.

Now we set this symbol foo:

CL-USER 48 > (setq foo 20)
20

CL-USER 49 > (baz 22)
440

We have successfully called it, even though FOO was not declared as a global function.

Let's check, if it is declared as special:

CL-USER 50 > (SYSTEM:DECLARED-SPECIAL-P 'foo)
NIL

Now we compile the function from above:

CL-USER 51 > (compile 'baz)
;;;*** Warning in BAZ: FOO assumed special
BAZ

The compiler says that it does not know of FOO and assumes that it is special.

This behaviour is undefined and implementations differ:

  • an interpreter might just use the global symbol value and not complain at all - see the LispWorks example above. That's relatively common in implementations.

  • a compiler might assume that the undefined variable is a special variable and warns. This is also relatively common in implementations.

  • a compiler might assume that the undefined variable is a special variable and also declare the variable to be special. This is not so common - the CMUCL did (does?) that by default. This behaviour is not common and not liked, since there is no standard way to undo the declaration.