Compiler macros are expanded in the compiled code only, and ignored by the interpreter.
When a DEFUN
form is EVAL
uated, 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;value
is lexical (defun adder-i (value) (lambda (x) (+ x value))) ⇒ADDER-I
; interpreted function;value
is 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-I
andADD-I-10
but notADDER-C
andADD-C-10
(funcall add-c-10 32) ⇒42
; as before (funcall add-i-10 32) ⇒44
;value
is 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 FUNCALL
s)
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 DEFUN
s 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-FORM
ERROR
was
SIGNAL
edEXT:SOURCE-PROGRAM-ERROR-DETAIL
ERROR
Mixing &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:
(DEFUN
foo (&OPTIONAL
a&KEY
b) (cons a b)) (COMPILE
'foo) WARNING: in FOO : Mixing&OPTIONAL
and&KEY
in lambda list (&OPTIONAL
A&KEY
B) is bad design FOO ; 1 ; NIL
These notes document CLISP version 2.49.93+ | Last modified: 2018-02-19 |