TAIL-RECURSION-OPTIMIZATION
The inability to do early binding is a barrier to doing traditional optimizations such as tail recursion removal. For example, the best a compiler can typically do right now when a function FOO calls itself tail recursively is approximately: (IF (EQ #'FOO ...what compiler expects...) ...fast jump... ...standard function calling sequence...)
Specifically, with SPEED=0, the compiler should not do early binding (for the sake of tracing, stack debugging, and reloading in interactive debugging), but with in other with higher speed settings, it is permitted to make such optimizations (except as discussed below).
Specify that the NOTINLINE declaration can be used within a function to inhibit early binding of a function name to its definition, regardless of the OPTMIZE SPEED setting.
Specify that the NOTINLINE proclamation can be used to globally inhibit early binding of a function name to its definition, regardless of the OPTMIZE SPEED setting.
DEFUN FACTORIAL-2 (X &OPTIONAL (N 1)) (COND ((= X 0) N) (T (FACTORIAL-2 (- X 1) (* N X)))))
The compiler is permitted to (but not required to) treat this as if the following had been written instead:
(DEFUN FACTORIAL-2 (X &OPTIONAL (N 1)) (LABELS ((FACTORIAL-2 (X &OPTIONAL (N 1))) (COND ((= X 0) N) (T (FACTORIAL-2 (- X 1) (* N X))))) (FACTORIAL-2 X N)))
#2: (DEFMACRO DEFUN-AUTOLOADING (NAME FILE) `(PROGN (PROCLAIM '(NOTINLINE ,NAME)) (DEFUN ,NAME (&REST ARGUMENTS) (LET ((OLD-ME #',NAME)) (LOAD ,FILE) (LET ((NEW-ME #',NAME)) (WHEN (EQ OLD-ME NEW-ME) (ERROR "Function ~S was undefined after autoload." ',NAME)) (APPLY NEW-ME ARGUMENTS)))))) (DEFUN-AUTOLOADING FOO "foo.lisp") (DEFUN BAR (X) (FOO X))
The compiler must not make assumptions about the contents of #'FOO. Therefore, the function BAR will always see the current definition of FOO even in the face of runtime redefinition.
Program modularity is of key importance to many Common Lisp programmers, and it would be rash to say that the compiler could simply violate function boundaries at whim. Nevertheless, for Common Lisp to successfully compete with other languages, it should be designed in a way that at least permits implementations to make this optimization.
This proposal is designed to achieve a workable compromise between issues of speed and debuggability.
Some implementations do early binding already even when it is not permitted. Such implementations have an unfair benchmark advantage over "correct but slow" implementations in the marketplace. This would even the odds for those implementations who would do the optimization if only it were correct.
Lucid Common Lisp does early binding, and so does not conform to CLtL in some cases.
The TI Explorer assumes a function will not redefine itself and does tail recursion removal at `higher optimization levels.'
SPEED>0.Lisp vendors who do this optimization even though it's technically not correct would continue have an unfair business advantage over vendors over those who respect the rules of the language.
Charles Hornig (Symbolics) observes that SPEED=0 is perhaps not quite the right criterion. The issue of whether absolute values of the OPTIMIZE qualities are what's of interest or only relative values of the different qualities is an open topic. For now, this proposal uses SPEED 0 just to be conservative. If everyone can agree on something broader, we could change the proposal. Alternatively, we can just adopt that part of the proposal `as is' and work on a separate proposal on how to deal with OPTIMIZE qualities.
David Gray has expressed reservations about this to the OPTIMIZE SPEED quality at all since he sees it as a semantic issue.
Masinter points out that there might be some relation of this to the issue FUNCTION-COERCE-TIME.