3.3 Using type-specific operations

3.3.1 Using fixnum operations

To produce a type-specific version of a Common Lisp operator, the Compiler must know both the types of the arguments and the type of the value of an expression. You can specify types as follows:

For example, the following code defines a function that sums a list of numbers:

(defun list-add (l)
  (let ((sum 0))
    (dolist (i l sum)
      (setq sum (+ i sum)))))

To increase the efficiency oflist-add, you should declare both the argument types and the result types of the expression. In the following code, thedeclare special form is used to declare the variablesi andsum to be of typefixnum:

(defun list-add (l)
  (let ((sum 0))
    (declare (fixnum sum))
    (dolist (i l sum)
      (declare (fixnum i))
      (setq sum (+ i sum)))))

Note that the value of the expression(+isum) is also implicitly declared to be of typefixnum because the value of the expression is assigned to sum, which has been declared to be of typefixnum. The Compiler is thus free to depend on these types and will use the fixnum-specific version of+.

(the value-type form)
The following example shows an alternate form of list-add that uses the special formthe to declare both the value type of the expression and the types of the list elements as they are retrieved:

(defun labels-list-add (l)
  (labels ((help-add (sum restl)  ; Define a recursive helper
                                  ; function.
             (declare (fixnum sum))
             (if (null restl) sum 
                   (the fixnum 
                        (+ sum (the fixnum (first restl))))
                   (rest restl)))))
    (help-add 0 l)))

Because both the argument types and the value type have been declared, the Compiler can use a fixnum-specific version of+.

You can useftype declarations to restrict arithmetic operators only in certain contexts. In many cases the result of applying arithmetic operators to fixnum values is not a fixnum unless the fixnum values are small. The expression (1+most-positive-fixnum) does not produce a fixnum value, for example. If the fixnum values are small enough, however, you can useftype declarations to restrict arithmetic operators. For example, the following declarations inform the Compiler that whenever the arguments to the declared operators are fixnum integers the value types will also be fixnums. The Compiler can thus use the fixnum forms of the operators:

(declare (ftype (function (&rest fixnum) fixnum) + -)
         (ftype (function (fixnum) fixnum) 1+ 1-))

Often only fixnum arithmetic is needed in a program. The following example shows another form oflist-add that uses a singletype-reduce declaration to restrict all numerical quantities within the function:

(defun fixnum-list-add (l)
  (declare (type-reduce number fixnum))
  (let ((sum 0))
    (dolist (i l sum)
      (setq sum (+ i sum)))))

You can use type declarations to write fixnum-specific versions for generic routines. You must use caution, however, when defining fixnum-specific operators. Expressions that apply arithmetic operators to more than two arguments might not produce optimal compiled code. For example, the following expression cannot be fully optimized:

(the fixnum (+ (the fixnum x) (the fixnum y) (the fixnum z))))
Although each of the arguments and the result of the entire expression are declared as fixnums, the Compiler cannot assume that the intermediate results will also be fixnums.

The following macro defines a fixnum-specific addition operator. Note that it automatically expresses the sum in terms of binary operators and adds the necessary declarations:

(defmacro fixnum-plus (&rest args)
  (case (length args)
    (0 '0)
    (1 (first args))
    (2 '(the fixnum (+ (the fixnum ,(first args))
                       (the fixnum ,(second args)))))
    (t '(the fixnum
             (+ (the fixnum ,(first args))
                (fixnum-plus ,@(rest args)))))))

When this code is compiled, calls to fixnum-plus are coded directly into hardware add instructions.

The Advanced User's Guide - 9 SEP 1996

Generated with Harlequin WebMaker