When executing the below code in sbcl repl, i'm getting the 'undefined variable' warning for variables test-cases, n. I've gone through similar questions on the forum and the warning appears to occur if a variable is setf/setq'ed without defining first. But i have defined those variables using defparameter but still getting the warning.
One thing i noticed is, if i don't reference the variables in the format statement, warning is not occuring.
I've tried using defvar as well. but it is still throwing the warning.
can someone help me understand why the warning is thrown when used in a statment even if the variable is defined?
(defun main ()
(defvar test-cases 10)
(defvar l 12)
(defvar n 13)
(format t "~a ~a ~a" test-cases l n))
; in: DEFUN MAIN
; (FORMAT T "~a ~a ~a" TEST-CASES L N)
;
; caught WARNING:
; undefined variable: N
;
; caught WARNING:
; undefined variable: TEST-CASES
;
; compilation unit finished
; Undefined variables:
; N TEST-CASES
; caught 2 WARNING conditions
WARNING: redefining COMMON-LISP-USER::MAIN in DEFUN
The following explains why you have an error, but note that it is rarely necessary to define global variables from inside functions, most of the time you will use a local binding with LET.
Here is a reduced test case:
(defun foo () (defvar bar nil) bar)
At the time foo is being compiled, bar is undefined (assuming a fresh CL environment). This is why the compiler complains. If, however, you call foo, the variable will be declared (globally) and then its value will be returned.
The call to DEFVAR has an effect on the global environment only when it is executed, or at compile-time when it is a top-level form:
However, the compile-time side effects described below only take place when they appear as top level forms.
...
Side-effects: If a defvar or defparameter form appears as a top level form, the compiler must recognize that the name has been proclaimed special. However, it must neither evaluate the initial-value form nor assign the dynamic variable named name at compile time.
Thus, compiling a call to defvar inside a function body does not declare the symbol as a special variable.
Related
SBCL generates spurious style warnings about undefined functions. (The functions are defined, just later in the file.) I want to solve this problem once and for all. Fortunately, there is a way to do this:
(declaim (sb-ext:muffle-conditions style-warning))
The downside is that CCL, for obvious reasons, barfs on a program containing the above. I try to solve this problem with a conditional:
(#+sbcl (declaim (sb-ext:muffle-conditions style-warning)))
but now SBCL is unhappy: "illegal function call".
How do you put such a declaim into a portable program?
Note that while the existing answer is right, disabling warnings is not a good practice. In your case, it is probably not necessary.
Common Lisp has a notion of compilation unit, where multiple definitions are grouped together. This gives a chance for the compiler/interpreter to take care of cross-references among functions (an interpreter could collect warnings and keep only those that are not found later, for example).
For example, in file #P"/tmp/foo.pl":
(defun mut-rec-foo (x)
(when (plusp x)
(mut-rec-bar (1- x))))
(defun mut-rec-bar (x)
(print x)
(mut-rec-foo (1- x)))
Do not evaluate anything in the file; instead do:
(compile-file #P"/tmp/foo.pl")
; compiling (DEFUN MUT-REC-FOO ...)
; compiling (DEFUN MUT-REC-BAR ...)
; /tmp/foo.fasl written
; compilation finished in 0:00:00.002
No warning. You can then call (load #P"/tmp/foo.fasl") to have the definitions in your current lisp environment, without warnings.
Typically, ASDF and by extension Quicklisp use COMPILE-FILE, so your problem should disappear as soon as you bundle your files into a system.
You can also do:
(with-compilation-unit ()
(defun mut-rec-foo/bis (x)
(when (plusp x)
(mut-rec-bar/bis (1- x))))
(defun mut-rec-bar/bis (x)
(print x)
(mut-rec-foo/bis (1- x))))
Evaluating the whole block shows no warning for *EVALUATOR-MODE* being both :COMPILE or :INTERPRET.
What you witnessed happens when you evaluate each expression one after the other (or maybe one region after another one). There, the compiler has no way to know that the function already exists. Silencing the warning is the worse option, because you might actually have made an error.
If you know in advance that a function will exist, but not in your compilation unit (maybe it is only defined at runtime), the you can declaim that fact, as follows:
(declaim (ftype function my-function))
The above says that my-function must be assumed to be fbound to an object of type function. You could also give more information by refining what kind of function you claim it to be:
(declaim (ftype (function (number) (values string &optional)) num-to-string))
... for a function that accepts a number and returns exactly one value, a string.
(declaim (ftype (function () nil) forever-loop))
... for a function that accepts nothing and never return a value (loop or signals an error).
Omit the outer pair of parentheses:
#+sbcl (declaim (sb-ext:muffle-conditions style-warning))
As you are using declaim, I assume, that the declaration appears at the top-level of a compilation unit. If you need to group multiple top-level statements, you can wrap them all with a progn (which doesn't change the "top-level"-ness).
The reason SBCL did complain is, that its reader reads
((declaim (sb-ext:muffle-conditions style-warning)))
(as the :SBCL feature is present), which is simply a syntax error. CCL does not complain, because its reader reads
()
which is simply another way to spell nil.
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.
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..
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.
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.
Or in other words: Is it possible for a variable in CL not to be (part of) a symbol?
I think I may have a profound misconception about variables in CL.
I always thought CL has no variables, only symbols, and symbols have (among other properties) a name and a value cell (which is the variable).
And when someone said "variable x has the value 42" I thought it was short for "the value cell of the symbol named x stores the value 42".
But this is probably wrong.
When I type
> (let ((a 42))
(type-of 'a))
SYMBOL
; caught STYLE-WARNING:
; The variable A is defined but never used.
is the lexical variable a in this example a fully fleshed symbol whose value cell has been set to 42?
Because the warning The variable A is defined but never used suggests otherwise and it appears that the lexical variable is not the same thing as the symbol a in the following form (type-of 'a).
Common Lisp has two data types which have a special meaning for evaluation:
cons cells / lists -> used in Lisp source code, lists are Lisp forms
symbols -> used as names for various purposes
If you want to use them as data in Lisp code, then you have to quote them.
Both are used in the Lisp source code, but once you compile code, they may disappear.
Variables are written as symbols in the source code. But in compiled code they may go away - when they are lexical variables.
Example using SBCL:
a file with
(defun test (foo)
(+ foo foo))
Now we do:
CL-USER> (proclaim '(optimize (debug 0))) ; the compiler saves no debug info
; No value
CL-USER> (compile-file "/tmp/test.lisp")
; compiling file "/private/tmp/test.lisp" (written 23 MAY 2017 09:06:51 PM):
; compiling (DEFUN TEST ...)
; /tmp/test.fasl written
; compilation finished in 0:00:00.013
#P"/private/tmp/test.fasl"
NIL
NIL
CL-USER> (find-symbol "FOO")
FOO
:INTERNAL
The compiler has read the source code and created a compiled FASL file. We see that the symbol FOO is now in the current package. FOO names the variable in our source code.
Now quit SBCL and restart it.
Let's load the machine code:
CL-USER> (load "/tmp/test")
T
CL-USER> (find-symbol "FOO")
NIL
NIL
There is no symbol FOO anymore. It's also not possible to retrieve the lexical value of the variable FOO using the symbol FOO. There is no mapping (like some kind of explicit lexical environment) from symbols to lexical values.
The value cell is used for dynamic (AKA "special") variables, not lexical variables. Lexical variables are symbols in the source code, but they don't have any runtime relationship to the symbol (except for internal use by the debugger).
So if you wrote:
(let ((a 42))
(declare (special a))
(print (symbol-value 'a)))
it would work because the declaration makes it a dynamic variable, and then you can access the value in the function cell.
You are not checking the type of the bound variable a or its value but that of a literal constant symbol that happens to have the same name as the variable in your let form:
(let ((a 42))
(type-of 'literal-symbol))
; ==> symbol (since 'literal-symbol evaluates to a symbol, just like 'a does)
To check the type of the value of the binding a you do it without the literal quote:
(let ((a 42))
(type-of a))
; ==> (integer 0 281474976710655)
Here you actually check the type of the let bound value and it's an integer. Surprised that 42 is a number and not a symbol?
(let ((a 10) (b 'a))
(list a b))
; ==> (10 a)
The variable a and the quoted literal 'a are not the same. They just happen to look the same when displayed but 'a is data and a is code. In CL a compiler might use lists and symbols internally but what it is when its executing is entirely up to the implementation and in most implementations they stack allocate when they can and the code that evaluate a stack allocated variable would be replaced by something that picks the value at the index from the stack. CL has a disassemble function and if you check the output in SBCL from something you'll see it's more similar to the output of a C compiler than the original lisp source.
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?
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
Very shortly, you can think of setq, which is the expansion of setf you have observed, as doing only one half of what defvar or defparameter do:
Consider that defparameter does this:
(declaim (special x))
(setq x 10)
I.e. it both provides some meta-data (the data about what sort of thing x is) to the compiler (in this case it tells it that it is a "special" variable) and assigns value.
In particular, defvar will not behave like this, if it is a top-level form. The standard behaviour is to initialize the value-cell of the symbol only once, so its code will be even more complex, something that you can think of as:
(unless (boundp x) ; This is not entirely correct, because if the symbol
; is otherwise known to the environment, but is unbound
; defvar will not re-bind it, but I can't think of a way
; to mimic that behavior
(declaim (special x))
(setq x 10))
The meta-data provided to compiler may or may not have any effect on how the code will behave. In general, the meta-data is supposed to aid the compiler to make better judgement of the intent behind your code, and thus may result in optimizations. But it can also be useful for documentation or debugging.
You can read about special and declare in Hyperspec.
As far as i know you should avoid using setf(which expands to setq) with undeclared variables. The behavior can differ between implementations and even if your code in REPL works good, the compiled program can be bugged in unexpected place. You can see warning in clisp if you do something like this:
>(defun internal-setf () (setf some-var 10))
>(compile 'internal-setf)
WARNING: in INTERNAL-SETF : SOME-VAR is neither declared nor bound,
it will be treated as if it were declared SPECIAL.
I've tried to reduce it to the minimal example. The code runs without an error, producing the expected output. But it gives me a warning that my first variable is undefined. It seems that the second statement of progn doesn't "see" the results of the first statement. Thanks for the help!
(I originally did not have the progn construct in the code at all, but after getting this error I added it to see if that would force execution in order -- but the error is the same.)
Here's the code:
(let ((input (open "input.lisp")))
(progn (defvar var1 (read input))
(defvar arr1 (make-array var1 :initial-contents (read input))))
(close input))
(print var1)
(print arr1)
These are the contents of the file "input.lisp":
9
(10 8 6 4 2 4 6 8 10)
And this is the output I get from sbcl after executing (load "test.lisp"):
; in: DEFVAR ARR1
; (MAKE-ARRAY VAR1 :INITIAL-CONTENTS (READ INPUT))
;
; caught WARNING:
; undefined variable: VAR1
;
; compilation unit finished
; Undefined variable:
; VAR1
; caught 1 WARNING condition
9
#(10 8 6 4 2 4 6 8 10)
T
So, it seems to me that both definition statements are executing, but the second doesn't "see" the results of the first. It still constructs the array correctly because it's filled with the given initial-contents. But why isn't var1 already defined?
See the documentation for defvar in the Hyperspec:
If a defvar or defparameter form appears as a top level form, the compiler must recognize that the name has been proclaimed special.
This implies (and it seems to be the case for SBCL) that if a defvar appears as a non-top-level form, then the compiler need not recognize that the name has been declared. So how come your defvars are not being compiled as top level forms? See section 3.2.3.1, Processing of Top Level Forms (point 6) for the answer: the let surrounding your code causes it to be compiled as non-top-level forms.
So you need to defvar your variables at top level, and then assign them later on with setf inside the let.
Like this. It's also usually simpler to use with-open-file rather than open and close.
(defvar var1)
(defvar arr1)
(with-open-file (input "input.lisp" :direction :input)
(setf var1 (read input))
(setf arr1 (make-array var1 :initial-contents (read input))))
(print var1)
(print arr1)
The reason that you are having this trouble is that you are placing your code at top level in the file. This is a slightly unusual thing to do: the normal Lisp coding style is to put most of your code in function definitions, and then to call those functions when you need to run them.
For example, this would be a more typical way to write this kind of code, with the initialization code in its own function.
(defvar *var1* nil "Documentation for var1.")
(defvar *arr1* nil "Documentation for arr1.")
(defun init-from-file (file)
"Read *var1* and *arr1* from file."
(with-open-file (input file :direction :input)
(setf *var1* (read input))
(setf *arr1* (make-array *var1* :initial-contents (read input)))))
(when (null *var1*) (init-from-file "input.lisp"))