Compiler macros are expanded in the compiled code only, and ignored by the interpreter.
When a DEFUN form is EVALuated, the macros used there are
expanded, so they must be already defined, and their (re)definition
does not affect functions which are already defined.
This means that even the interpreted code is minimally compiled in CLISP.
Non-conforming code that does not follow the rule
“Special proclamations for dynamic variables must be made in the compilation environment.”
can produce quite unexpected results, e.g., observable differences between compiled and interpreted programs:
(defun adder-c (value) (declare(COMPILE)) (lambda (x) (+ x value))) ⇒ADDER-C; compiled function;valueis lexical (defun adder-i (value) (lambda (x) (+ x value))) ⇒ADDER-I; interpreted function;valueis lexical (defparameter add-c-10 (adder-c 10)) ⇒ADD-C-10; compiled function (defparameter add-i-10 (adder-i 10)) ⇒ADD-I-10; interpreted function (funcall add-c-10 32) ⇒42; as expected (funcall add-i-10 32) ⇒42; as expected (defvar value 12) ⇒VALUE; affectsADDER-IandADD-I-10but notADDER-CandADD-C-10(funcall add-c-10 32) ⇒42; as before (funcall add-i-10 32) ⇒44;valueis now dynamic!
Non-conformance. The code shown above has a SPECIAL proclamation (by DEFVAR)
for the variable value in the execution environment
(before the last two FUNCALLs)
but not in the compilation environment: at the moment
the ADDER-I function is defined,
value is not known to be a SPECIAL variable.
Therefore the code is not conforming.
The function ADD-C-10 was compiled before
value was declared SPECIAL, so the symbol value was
eliminated from its code and the SPECIAL declaration did
not affect the return value (i.e., (funcall
add-c-10 32) always returned 42).
On the opposite, function ADDER-I was not
compiled, so ADD-I-10
was interpreted.
Whenever ADD-I-10 is executed, its definition is
interpreted all over again. Before DEFVAR, value is evaluated as
a lexical (because it is not declared SPECIAL yet), but after
DEFVAR, we see a globally SPECIAL symbol value which
can have only a global SYMBOL-VALUE (not a local binding), and thus
we are compelled to evaluate it to 12.
This behavior was implemented intentionally to ease interactive
development, because usually
the ADDER-I above would be followed by a
(forgotten) DEFVAR.
When a user compiles a program, the compiler is allowed to
remember the information whether a variable was SPECIAL or not,
because that allows the compiler to generate more efficient code,
but in interpreted code, when the user changes the state of a variable,
he does not want to re-evaluate all DEFUNs that use the variable.
[ANSI CL standard] gives the implementation freedom regarding interpreted evaluation, how much it wants to remember / cache, and how much it wants to re-evaluate according the current environment, if it has changed. CLISP implements ad-hoc look-up for variables (but not for macros, see Section 3.2.2.2, “Minimal Compilation sec_3-2-2-2”).
Hash tables are externalizable objects.
Both COMPILE and EVAL may SIGNAL the EXT:SOURCE-PROGRAM-ERROR
CONDITION which derives from PROGRAM-ERROR and which contains
additional slots with accessors
EXT:SOURCE-PROGRAM-ERROR-FORMERROR was
SIGNALedEXT:SOURCE-PROGRAM-ERROR-DETAILERRORMixing &OPTIONAL and &KEY. It is a bad design to have both &OPTIONAL and &KEY in the
same lambda list, especially if the number of optional arguments is even:
the users will often forget to supply optional arguments when supplying
keys, e.g., (
instead of READ-FROM-STRING string :START 5)(.
This is why the CLISP compiler issues a READ-FROM-STRING string t nil :START 5)STYLE-WARNING in such cases:
(DEFUNfoo (&OPTIONALa&KEYb) (cons a b)) (COMPILE'foo) WARNING: in FOO : Mixing&OPTIONALand&KEYin lambda list (&OPTIONALA&KEYB) is bad design FOO ; 1 ; NIL
| These notes document CLISP version 2.49.93+ | Last modified: 2018-02-19 |