Skip to content

Tutorial 3: Compile Time Support

Mark Cox edited this page Nov 17, 2017 · 1 revision

The dispatching mechanism currently used in specialization store is a binary tree whereby sets of specializations are ruled in or out according to a predicate applied to one of the argument types. The overhead of this approach is reasonably low, but there are cases where it should be avoided.

Store functions can select a specialization at compile time using type information found in the form requesting the function application or declarations in the current lexical environment.

Users can communicate type information to a store function using any of the following approaches:

(defstore example (a))

;; Constants
(example 0)

;; THE forms
(let* ((x 0))
  (example (the fixnum x)))

;; Macros/symbol macros and THE forms
(let* ((x 0))
  (symbol-macrolet ((a (the fixnum x)))
    (example a)))

;; Variable declarations (only available on implementations supporting CLtL2)
(let* ((x 0))
  (declare (type fixnum x))
  (example x))

;; Function declarations (only available on implementations supporting CLtL2)
(locally (declare (ftype (function (fixnum) fixnum) solve))
  (example (solve 0)))

A user can request a specialization to perform one of the following compile time optimizations:

  1. Inlined specializations.
  2. Named specializations.
  3. Expand functions.

Inlined Specializations

The code associated with a specialization can be inlined if users specify :inline t when defining a specialization.

(defstore example (object))

(defspecialization (example :inline t) ((a float)) t
  (1+ a))

(let* ((fn (compiler-macro-function 'example)))
    (funcall fn '(example (the float x)) nil))

=> ((lambda (a)
      (declare (type float a))
      (the t (progn (1+ a))))
    (the float x))

Named specializations

A store function application can be replaced with a direct invocation of the function associated with a specialization. The specialization option :name specialization-name is used to specify the function binding in the global environment.

(defstore example (object))

(defspecialization (example :name %example/string) ((a string)) t
  (concatenate 'string "Info: " a))

(let* ((fn (compiler-macro-function 'example)))
    (funcall fn '(example (the string x)) nil))

=> (%example/string (the string x))

Expand functions

The most general compile time facility provided to users are specialization specific compile time macro functions. These functions are referred to as expand functions.

Expand functions can be included in the specialization definition when using the long form operator define-specialization.

(defstore example (a))

(define-specialization example ((int integer)) t
  (:function (lambda (int)
               (format t "~&Runtime: ~A.~%" int)))
  (:expand-function (compiler-macro-lambda (int)
                      `(format t "~&Compile time: ~A -> ~A.~%" ',int ,int))))

The compiler-macro-lambda operator above is a convenient way to express anonymous macro functions i.e. compiler-macro-lambda is to define-compiler-macro as lambda is to defun.

Clone this wiki locally