Compilation Tips
----------------
Here are some tips for making compiled code run fast(er):
* Instead of using `while' loops to traverse lists, use `mapc' or
tail recursion.
For example you might code a function to scan a list using
iteration through a `while' loop:
(defun scan-list (lst elt)
"Search the LST for an element similar to ELT.
Return it if one is found."
(catch 'return
(while (consp lst)
(when (equal (car lst) elt)
(throw 'return elt))
(setq lst (cdr lst)))))
As well as obscuring what is actually happening, this will
probably be fairly slow to execute. A more elegant solution is to
use tail-recursion:
(defun scan-list (lst elt)
(if (equal (car lst) elt)
elt
(scan-list (cdr lst) elt)))
An alternative idiom is to map an anonymous function over the list
using the `mapc' function:
(defun scan-list (lst elt)
(catch 'return
(mapc (lambda (x)
(when (equal x elt)
(throw 'return elt)))
lst)
nil))
In fact, the compiler knows that calls to `mapc' with a constant
lambda expression can be open-coded, so it will code the list
traversal directly using the virtual machine stack.
However, in most cases the execution time differences are likely to
negligible.
* In some cases the functions `member', `memq', `assoc', etc... can
be used to search lists. Since these are primitives written in C
they will probably execute several times faster than an equivalent
Lisp function.
So the above `scan-list' example can again be rewritten, this time
as:
(defun scan-list (lst elt)
(car (member elt lst)))
* All conditional structures are equivalent when compiled (they are
all translated to `cond' statements), so use whichever is the
easiest to understand.
* A certain amount of constant folding is performed. If a function is
known to be free of side effects, and all its arguments are
constants, then it is evaluated at compile-time, and the result
folded into the program in its place. For example
(logor (lsh 1 6) x)
==> (logor 32 x)
* Careful use of named constants (Note:Defining Variables) can
increase the speed of some programs. For example, in the Lisp
compiler itself all the opcode values (small integers) are defined
as constants.
It must be stressed that in some cases constants may _not_ be
suitable; they may drastically increase the size of the compiled
program (when the constants are `big' objects, i.e. long lists) or
even introduce subtle bugs (since two references to the same
constant may not be `eq' whereas two references to the same
variable are always `eq').
* Many primitives have corresponding byte-code instructions; these
primitives will be quicker to call than those that don't (and
incur a normal function call). Currently, the functions which have
byte-code instructions (apart from all the special forms) are:
`cons', `car', `cdr', `rplaca', `rplacd', `nth', `nthcdr', `aset',
`aref', `length', `eval', `+', `*', `/', `%', `mod', `lognot',
`not', `logior', `logand', `logxor', `equal', `eq', `=', `/=',
`>', `<', `>=', `<=', `1+', `1-', `-', `set', `lsh', `zerop',
`null', `atom', `consp', `listp', `numberp', `stringp', `vectorp',
`throw', `boundp', `symbolp', `get', `put', `signal', `return',
`reverse', `nreverse', `assoc', `assq', `rassoc', `rassq', `last',
`mapcar', `mapc', `member', `memq', `delete', `delq', `delete-if',
`delete-if-not', `copy-sequence', `sequencep', `functionp',
`special-form-p', `subrp', `eql', `max', `min', `filter',
`macrop', `bytecodep', `bind-object'.
* When a file is being compiled each top-level form it contains is
inspected to see if it should be compiled into a byte-code form.
Different types of form are processed in different ways:
* Function and macro definitions have their body forms compiled
into a single byte-code form. The doc-string and interactive
declaration are not compiled.
* If the form is a list form (Note:List Forms) and the
symbol which is the car of the list is one of:
`if', `cond', `when', `unless', `let', `let*', `catch',
`unwind-protect', `error-protect', `with-buffer',
`with-window', `progn', `prog1', `prog2', `while', `and',
`or', `case'.
then the form is compiled. Otherwise it is just written to
the output file in its uncompiled state.
If your program contains a lot of top-level forms which you know
will not be compiled automatically, consider putting them in a
`progn' block to make the compiler coalesce them into one
byte-code form.