Implementation

$Revision: 5.0.2.10 $

The document introduction.htm provides an overview of the Allegro CL documentation with links to all major documents. The document index.htm is an index with pointers to every documented object (operators, variables, etc.) The revision number of this document is below the title. These documents may be revised from time to time between releases.

1.0 Implementation introduction
2.0 Data types
3.0 Characters
4.0 Autoloading
    4.1 Where the autoloaded files are located
    4.2 Common Lisp symbols
    4.3 Major extensions
    4.4 How to load modules
5.0 Miscellaneous implementation details
    5.1 Extensions to cl:make-package, cl:disassemble, cl:open
    5.2 cl:directory
    5.3 Reader macros and cl:*features*
    5.4 cl:random
    5.5 cl:make-hash-table
    5.6 cl:make-array
6.0 Allegro CL and the ANSI CL standard
    6.1 Compatibility with pre-ANSI CLtL-1 in Allegro CL
    6.2 Other package changes and compile-time-too behavior
    6.3 The function data type
    6.4 CLOS and MOP
    6.5 CLOS and MOP conformance
    6.6 CLOS optimization
7.0 Function specs
8.0 Some low-level functionality
   Windows: GetWinMainArgs2
9.0 Compliance with the ANSI specification

1.0 Implementation introduction

The Common Lisp standard is deliberately vague on many of the specifics of an implementation. The authors of that book were, correctly, aware that implementation details are dependent on the nature of the hardware and the operating system, as well as the differing priorities of the implementors and the different user communities. This document details some of the specifics of the implementation of and extensions in Allegro CL.

2.0 Data types

Allegro CL contains all of the required Common Lisp data types. Fixnums are signed 30-bit quantities. Bignums may be as large as 2**[1,048,576]. There are two distinct floating-point types. Short-float and single-float are equivalent. Double-float and long-float are equivalent. The distinct array data types are the following (in the case of the simple arrays, we use suspension points, `...', to indicate that there may be any number of dimensions):

(array t)
(array bit)
(array (unsigned-byte 4))

(array (unsigned-byte 8))

(array (unsigned-byte 16))
(array (unsigned-byte 32))
(array character
)
(array single-float)
(array double-float)
(array (complex single-float))
(array (complex double-float))
(array (signed-byte 8))
(array (signed-byte 16))
(array (signed-byte 32))
(simple-array t (* ...))
(simple-array bit (* ...))
(simple-array (unsigned-byte 4) (* ...))
(simple-array (unsigned-byte 8) (* ...))
(simple-array (unsigned-byte 16) (* ...))
(simple-array (unsigned-byte 32) (* ...))
(simple-array character (* ...))
(simple-array single-float (* ...))
(simple-array double-float (* ...))
(simple-array (signed-byte 8) (* ...))
(simple-array (signed-byte 16) (* ...))
(simple-array (signed-byte 32) (* ...))

3.0 Characters

X3J13, the ANSI subcommittee chartered to propose a specification for the forthcoming ANSI Common Lisp, has voted to make several changes to Common Lisp's treatment of characters. The intent of these changes is to clean up ideas that are felt not to have worked out in pre-ANSI Common Lisp as well as to allow for Common Lisp to be extensible to international languages. Unfortunately, some of these changes affect backward compatibility and storage efficiency. The result is that Franz Inc. has had to make some user-visible changes that may affect code which explicitly makes arrays or vectors of type character.

X3J13 has removed discussion of bit and font attributes of characters from the Common Lisp language. The string-char type specifier has also been removed from the language by X3J13. Finally, strings are now equivalent to (vector character) for creation purposes. X3J13 allows characters to be attributed with bit/font features as described in CLtL, but in an implementation-dependent way.

ANSI compatible Allegro CL continues to support font/bit attributes of characters. For example, the reader and printer acts on such characters in the pre-ANSI CL way (e.g., #\control-a is #\a with the control bit set, #3\meta-b is #\b with font 3 and the meta bit set). What's more, functions operating on bits and fonts from pre-ANSI CL (e.g., string-char-p, char-bits, char-font, make-char) are available in the cltl1 package.

Because Franz Inc. wants to achieve as much backward compatibility as possible with code using pre-ANSI font/bit attributed characters, and because Franz Inc. also wants to represent strings at least as efficiently as they have been in pre-ANSI versions of Allegro CL, difficulties arise in representing attributed characters in strings (which are now vectors of characters instead of vectors of string-chars). What ANSI-compatible Allegro CL does is to specify that it is an error to store attributed characters in a string. What in fact happens if one tries to do so is that the attributes are stripped. Thus an attributed character that has been stored in an array and extracted is no longer attributed and no longer EQL to its previous value.

Although this behavior violates the spirit of how elements are stored in arrays, this behavior was chosen by Franz Inc. because (a) pre-ANSI CL code using fonts/bits will not have been storing attributed characters into strings since it has always been an error to do so, and (b) representing strings as arrays that can hold attributed characters would have made strings less efficient and incompatible with existing foreign function code that uses strings.

In other words, portable ANSI CL code should not notice this compromise and pre-ANSI CL code should mostly be able to run as before with very little source change. The one area where portable pre-ANSI CL may run into problems is in places where the character type specifier is explicitly specified in calls to make-array, or to sequence functions that create a vector. (Such sequence functions include coerce, map, concatenate, etc.) These places in pre-ANSI CL where the character type specifier is used should most likely be changed to specify the t type specifier. In pre-ANSI versions of Allegro CL (array character) was equivalent to (array t).

4.0 Autoloading

Allegro CL has the ability to autoload certain files and modules. In order to keep the size of the system down by excluding parts not always needed, some of Allegro CL is not included in the system when it is built. These parts must be loaded in when they are required. This section describes how that code is loaded in.

4.1 Where the autoloaded files are located

All the fasl files which have the potential to be autoloaded are part of the Allegro CL library. All the files are collected into a single file called the bundle file. Its name is (in the default) files.bu and it is located in the Allegro directory. This file contains a set of fasl files which can be loaded individually (the whole file is not loaded when a part is). The function excl:bundle-pathname returns the pathname of the bundle file.

4.2 Common Lisp symbols

Code for some Common Lisp functions and macros (notably trace, inspect, and step) are contained in modules separate from the default binary. (The modules are called :trace, :inspect, and :step.) Whenever any Common Lisp function or macro is called, the necessary module will be loaded automatically. Note that using auxiliary features provided as extensions (such as referring to the variable excl:*trace-print-length*) will not cause the module to be loaded. Even though the modules can be automatically loaded, we recommend explicitly loading those that you need with a call to require, as described below.

4.3 Major extensions

The code for major extensions, such as the foreign function interface or multiprocessing, also is loaded when needed instead of being in the default Lisp binary. Again, calls to some functions will cause the correct module to be loaded, but we recommend loading the module before using the facility, using require, as described next.

4.4 How to load modules

While most modules will be loaded automatically when an important function or macro defined in the module is called, you have to load modules explicitly to use some of the less central functionality. Some users also prefer to explicitly load modules in order to save waiting when the module is actually needed.

To load a module with require, simply enter the form:

(require :module-name)

It is useful to put this form at the beginning of any source file containing code which uses symbols in the module. It is not an error to call require when the module is already loaded.

5.0 Miscellaneous implementation details

This section certain extensions to Common Lisp and those details of implementation.

5.1 Extensions to cl:make-package, cl:disassemble, cl:open
5.2 cl:directory
5.3 Reader macros and cl:*features*
5.4 cl:random
5.5 cl:make-hash-table
5.6 cl:make-array

5.1 Extensions to cl:make-package, cl:disassemble, cl:open

Certain standard Common Lisp functions have been extended in minor ways in Allegro CL. Elsewhere we describe changes to load (1.0 Using the load function in loading.htm for the general implementation, 1.4 Load foreign code with cl:load in foreign_functions.htm for loading foreign code) and cl:sleep ( in 5.0 Process functions and variables (both models) multiprocessing.htm, making it work on a per-process basis). Those functions were extended to do something essentially new (load to load foreign functions and fasl files in libfasl mode, sleep to work on single processes). The extensions mentioned in this section refer to changes in the semantics of some Common Lisp functions which affect the way they are ordinarily used. The sort of changes done include allowing strings denoting objects as input as well as the object itself. In some case we have added boolean variables which control the extended behavior, allowing you to decide exactly how you want Lisp to work.

[Function]
common-lisp:make-package

Arguments: package-name &key use implementation-packages

The implementation-packages keyword argument is an Allegro CL extension described fully in packages.htm. Its value should be a list. Otherwise, this function works as specified in the ANSI specification. The default for the use argument is implementation-dependent. The default in Allegro CL is a list containing one element, the common-lisp package.

[Function]
common-lisp:disassemble

Arguments: name-or-compiled-function &key absolute references-only recurse

The standard common-lisp:disassemble does not have any keyword arguments. Both are extensions which are likely not supported in implementations of Common Lisp other than Allegro CL.

In standard CL, name-or-compiled-function should be a function-object, a lambda expression, or a symbol with a function definition. Allegro CL also accepts function names which are lists as well (see 7.0 Function specs for a discussion of function names which are lists).

name-or-compiled-function can also be a string. A string is interpreted as naming a foreign (C or Fortran) function. The string must match the name identified by applying nm (or similar system function) to the current symbol table. This is often the result of applying ff:convert-to-lang to the routine name, but there are exceptions -- e.g. Lisp internal routines typically do not have a prepended underscore. name-or-compiled-function can also be a codevector. These are extensions to Common Lisp.

If the value of the absolute keyword argument is nil (the default), then relative pc addresses are given, starting at 0. If the value of absolute is non-nil, addresses are given as absolute addresses. Note that these addresses are consistent within a single disassembly, but any gc activity may have moved the code vector by the time the disassembly is done.

The recurse keyword argument, if true, causes internal functions to be disassembled after the specified function. It defaults to t if the name-or-compiled-function represents a function and if references-only is not specified.

If the references-only keyword argument is specified non-nil (its default value is nil) then no disassembly is printed. Instead, a list is returned of all references the function identified by the required argument makes (from either the function object or the global table) to any Lisp object.

There are other keyword arguments to cl:disassemble but they are not for programmer use.

[Function]
common-lisp:open

Arguments: file &key direction element-type if-exists if-does-not-exist class &allow-other-keys

The specification of this Common Lisp function in Common Lisp: the Language allows a great deal of latitude to the implementation since interfacing with file systems is hard to specify generally. Here we only discuss the if-exists keyword argument.

The if-exists argument is looked at only if the direction argument is specified as :io or :output. In that case the following values are allowed for if-exists and have the effect described.

The open function has been further extended to take a class keyword argument. open passes this argument to make-instance when it creates the stream, and as with make-instance, the argument may be a stream class object or a symbol naming such a class. If the class argument is not supplied or is nil, open selects one of the following built-in classes according to the direction and element-type arguments:

excl::character-input-file-stream
excl::character-output-file-stream
excl::character-bidirectional-file-stream
excl::binary-input-file-stream
excl::binary-output-file-stream
excl::binary-bidirectional-file-stream

These classes all contain file-stream and are variously mixed with

fundamental-character-input-stream
fundamental-character-output-stream
fundamental-binary-input-stream
fundamental-binary-output-stream

Although the file-stream subclasses returned by open are all instantiable, at present they require hidden initialization (for element-type upgrading, buffer allocation, etc.) and therefore they should only be created using open. It is fine to further specialize them, but you are required to create instances of your specializations of these stream classes using the :class keyword argument to open rather than by calling make-instance yourself.

open is also modified with &allow-other-keys and &rest to pass all keyword arguments as initialization arguments to make-instance. This has the unfortunate side effect of removing error checking for misspelled keyword arguments. A useful future enhancement might be to code some explicit checks which are executed when the class keyword argument is not given.

See streams.htm.

5.2 cl:directory

The directory function has had a keyword argument added to it to assist in recursive walks down a directory tree. (Note that even though the new argument is not specified, Common Lisp: the Language says the following about directory: `It is anticipated that an implementation may need to provide additional parameters to control the directory search. Therefore directory is specified to take additional keyword arguments so that implementations may experiment with extensions, even though no particular keywords are specified here.')

[Function]
common-lisp:directory

Arguments: path &key directories-are-files

Returns a list of pathnames matching path, which may be a pathname, string, symbol or stream. Returns nil if there is no match.

If the keyword argument directories-are-files is specified non-nil (the default), this function will return directories as files (that is pathnames with name and/or type components non-nil). If the argument is nil, directories are returned as directories (pathnames with name and type components nil). In the latter case it is possible to walk down a directory tree recursively using directory.

The elements of the list returned by directory is in the same order as returned by the associated system function (e.g. readir() on UNIX).

5.3 Reader macros and cl:*features*

[Reader macro]
#+(version>= ...)/#-(version>= ... )

We have extended the #+ and #- reader macros to accept (version>= N [ M]) as an argument. It is interpreted to mean that the form following will only be read if the version (also called release) of Allegro CL is greater than or equal to N.M. The N must be supplied. The M is optional. Both must be integers. With #+, version>= signifies read the next form only if the version is greater than or equal to N.M. With #-, it means read the next form only is the version is less than N.M. For example, because of an X3J13 change, the element type for an array of characters is character in release 4.1 and later (including 4.3) and string-char is earlier releases. To have code work in all Allegro CL releases, do the following:

(make-array 3 :element-type #+(version>= 4 1) 'character
              #-(version>= 4 1) 'string-char)

Warning: while most Common Lisp implementations (including Allegro CL prior to version 4.1) ignore `(version>=...)', it is possible that an implementation would signal an error upon encountering it. As a workaround for truly portable code, use:

#+(and allegro-version>= (version>=...))

Because :allegro-version>= is (presumably) only on the *features* list of Allegro CL 4.1 (and later), this will fail in all versions without version>= having to have a definition.

[Variable]
common-lisp:*features*

This standard Common Lisp variable can be used with the #+ and #- reader macros to conditionalize code for different Lisp implementations and releases. The exact value is different in every version of Allegro CL. Here are some useful values which may or may not be in your version. Please check the value of *features* in your version to see exactly what is there. The function excl:featurep can be used to test whether a feature is present of not.

Table 3.3: Features present or missing from *features* in Allegro CL 5.0

Feature

Meaning and use

:allegro Unique to Allegro CL. Present in all versions on all platforms. Use this to distinguish Allegro CL from other Lisp implementations.
:x3j13 Purports to conform to some version of Common Lisp specified by the ANSI X3J13 committee. Present in Allegro CL version 4.2, 4.3, and later.
:cltl2 Purports to conform to Common Lisp: the Language, 2nd ed. Since ANSI Lisp has diverged, :x3j13 and :cltl2 should not both be present. Not present in Allegro CL 4.2, 4.3, or later. Present in some earlier versions.
:draft-ansi-cl-2 Purports to conform to the second draft ANSI standard. Allegro CL does so, so :draft-ansi-cl-2 is present in Allegro CL 5.0
:ansi-cl Purports to conform to ANSI Common Lisp standard. The standard is now (since early 1996) final. Present in Allegro CL starting with version 4.3.
:dynload Foreign loading is done by dynamic linking of shared libraries/objects. The next three features are types of dynamic loading. See foreign_functions.htm.
:dlfcn Uses dlopen() to link foreign code.OS examples: Solaris, IRIX, Dec Unix, AIX. See foreign_functions.htm.
:dlhp Uses shl_load to link foreign code. HP only. See foreign_functions.htm.
:dlwin Uses LoadLibrary to link foreign code. Windows machines only. See foreign_functions.htm.
:dlld Loads .o files into image with ld. No 5.0 version uses this.
:os-threads Multiprocessing model uses native threads. Other model is the non :os-threads model (no special feature) where processes are managed within Lisp. See multiprocessing.htm.
:mswindows Appears in versions running on Windows machines. Use #-mswindows for Unix.
:sparc This feature appears on versions that run on machines with a Sparc processor (e.g. Sun 4's and Sparcstations). A similar platform-naming feature appears in all implementations and allows differentiating between machines. Look for the feature in your version.
:big-endian Platform uses the big-endian method of representing numbers.
:little-endian The platform uses the little-endian method of representing numbers.
:allegro-v5.0 Present in Allegro CL version 5.0. See also #+(version>= reader macro defined above. Both it and this feature are useful for conditionalizing code to run on different releases of Allegro CL.

5.4 cl:random

There are two random number generators used in Allegro CL, depending on the argument to random. One is fast, efficient, and does no consing but is only used when the argument is 1.0f0 (i.e.single-float 1.0) or a fixnum. The other, which is slower and less efficient and conses a great deal, is used when the argument to random is something other than 1.0f0 or a fixnum.

We recommend that users interested in random floats of magnitude X do

(* x (random 1.0f0))

rather than

(random x)

[Function]
cl:random

Arguments: number &optional state

Returns a pseudo-random number uniformly distributed between 0 and (- number 1) if number is an integer and between 0 (inclusive) and number (exclusive) if number is real. number must be real and positive. state should be a random-state object. If supplied, it will be made the state while the returned value is calculated.

If number is a fixnum or the single-float 1.0, the algorithm used to generate the result is Algorithm A on page 27 of Art of Computer Programming, volume 2, 2nd edition, by Donald Knuth (published by Addison-Wesley). If number is any other value, a linear-congruential generator using 48 bit integers for the seed and multiplier is used. because 48 bit integers are bignums, random with an argument other than a fixnum or the single-float 1.0 is very inefficient and not recommended.

A "random" random state, generated by (make-random-state t), uses cl:get-universal-time for its starting value. If you need many different "random" random states, do not generate them in a tight loop because cl:get-universal-time might return the same value more than once within the loop (cl:get-universal-time has a resolution of one second and a tight loop can run many many times in one second). Put a (sleep 1) in the loop to ensure cl:get-universal-time returnes different values. (Two initial values differing only in the last digit will produce different seeds.) Compare:

(dotimes (i 5)
  (print (make-random-state t)))

with

(dotimes (i 5)
  (sleep 1)
  (print (make-random-state t)))

5.5 cl:make-hash-table

[Function]
cl:make-hash-table

Arguments: &key test size rehash-size rehash-threshold hash-function values weak-keys

Hash tables with standard tests (eq, eql, equal, and equalp) have been optimized in Allegro CL to make putting values into and getting values from a hash table fast. eq hashtables are the fastest, followed closely by eql, and then equal and equalp.

Allegro CL has also extended make-hash-table in several ways:

  1. to accept the (non-standard) hash-function keyword argument,
  2. to allow for weak hashtables, and
  3. to allow for valueless hashtables.

The hash-function keyword argument allows further specialization when standard functionality is inefficient (usually because of excessive collisions caused by bunching of the hash codes of the data). Code that uses the hash-function argument is not portable Common Lisp, of course.

If specified, the value from hash-function should be a function of one argument which reproducibly returns an integer between 0 and 65535 (inclusive) when applied to any Lisp object intended to be used as a hash key. Reproducibly here means the function will return the same value on equivalent objects whenever it is called. hash-function defaults to sxhash except when test is one of the four standard tests (eq, eql, equal, equalp) when hash-function defaults to an internal function optimized for that test. (For equal and equalp, the hash-function is an internal version of sxhash.)

test should be a symbol naming a function of two arguments that returns t or nil as two keys are or are not equivalent. The standard values for test are eq, eql, equal, and equalp (or the associated function objects #'eq etc.) but any test function can be specified. (But note (1) that symbol is reserved for internal use. test should not be specified 'symbol in application or user code and (2) the value must be a symbol naming a function, not a function object; the four standard function objects listed just above are accepted as values but no other function objects.) If hash-function is specified, it is the programmer's responsibility to ensure the test function and the hash function work together correctly and consistently.

weak-keys defaults to nil, which specifies the default behavior. When weak-keys is specified as non-nil, the keys of the resulting hash table are treated specially by the garbage-collector: When a key in such a hash table has no more references to it, the entire entry is removed from the hash table, and the hash-table-count is decremented. This entry removal will occur regardless of whether :values :weak is specified (which by itself will never affect the hash-table-count, but only the value of an entry). See gc.htm for information on weak objects.

values defaults to t, which specifies that the hash table will contain both a key and a value for each entry. If values :weak is specified, then the hash table will only hold the value as long as it is referenced non-weakly by some other object. If no other objects reference the value, it becomes nil and a gethash on the key will return nil for the value (the value is collected by the gc). If values is specified as nil, then a sans values hash table is created, and only keys are stored as the actual values. For this kind of hash-table, maphash will call the function with a nil as the value argument, in place of an actual value (but the key will be passed in as usual). Also, gethash returns the stored key as the value (which is not necessarily eq to the given key argument), and a new function excl:puthash-key is defined for storing into these hash-tables.

5.6 cl:make-array

[Function]
cl:make-array

Arguments: dims &key allocation element-type weak
[and other standard CL keyword args not listed here]

allocation is discussed first and then weak.

allocation: make-array, a standard Common Lisp function, has been extended to accept the allocation keyword argument. The value of this argument must be one of the following keywords (the default is :new, which produces the behavior of earlier releases).

Value of allocation argument Meaning
:new Allocate the new array data in new space (the usual behavior). Any array element type accepted. This is the default.
:old Allocate the new array data in old space immediately (without waiting for it to survive for the required number of scavenges). Any array element type accepted.
:static Allocate the new array in malloc (foreign) space. The array will never be touched by the garbage collector and must be deallocated explicitly. Only a restricted number of element types are supported for static arrays. They are listed below. :malloc and :static are synonyms.
:malloc
:static-reclaimable Allocate the new array data in malloc (foreign) space and the header in Lisp space. The data will never be touched by the garbage collector but it will be deallocated when there are no pointers from Lisp (using a finalization). Only as restricted number of element types are supported for static arrays. They are listed below.
:lispstatic-reclaimable Allocate the new array in malloc (foreign) space. The array will never be touched by the garbage collector until there are no pointers from Lisp, at which point the whole array will be deallocated explicitly. Any Lisp type can be contained in the array.

allocation is not a standard Common Lisp argument to make-array so programmers may wish to conditionalize it with #+allegro to preserve code portability.

If allocation is :static or :malloc or :static-reclaimable, element-type must be specified and be one of the following:

bit
(signed-byte 8)
(unsigned-byte 4)
(unsigned-byte 8)
(signed-byte 16)
(unsigned-byte16)
(signed-byte 32)
(unsigned-byte 32)
character
single-float
double-float
(complex single-float)
(complex double-float)

Having created a static array, you may wish to free it. To do this, first pass the array to the function lispval-other-to-address, which will return an address (an integer). That address can be passed to aclfree. Note: if you reference the array after it has been freed, you will get garbage values. If you set a value in the array after it has been freed, you may cause Lisp to fail.

weak: make-array, a standard Common Lisp function, has been extended to accept the weak keyword argument. weak is not a standard Common Lisp argument to make-array so programmers may wish to conditionalize it with #+allegro to preserve code portability. weak may be true (meaning create a weak array) or nil (meaning create a standard array). The default is nil.

A Lisp object becomes garbage when nothing points to or references it. The way the garbage collector works is it finds and identifies live objects (often then moving them somewhere). Whatever is left is garbage. Weak arrays allow pointers to objects which will not, however, keep them alive. If one of these pointers exists, the garbage collector will see the item and (depending on the circumstances), either keep it alive or abandon it.

If you specify weak true, you cannot specify the non-standard allocation argument or the standard displaced-to argument. The only values accepted for the standard element-type argument are those for which no specialized array type for that element-type is defined (i.e. cl:upgarded-array-element-type applied to element-type should return t, which in essense means you should not specify element-type).

See 10.1 Weak ararys and hashtables in gc.htm for mroe information on weak arrays.

6.0 Allegro CL and the ANSI CL standard

Allegro CL 5.0 is an implementation of Common Lisp as specified by the ANSI X3J13 committee. The standard of conformance has been accepted by ANSI as final. ANSI is the American National Standards Institute, and the X3J13 committee prepared the ANSI standard for Common Lisp.

Common Lisp was originally specified in Common Lisp: the Language, 1st edition (CLtL-1). That standard is now out of date. Common Lisp: the Language, 2nd edition (CLtL-2) describes an earlier version of the ANSI standard. It is still used but please understand that the final ANSI standard has diverged in a number of ways from CLtL-2, so CLtL-2 is no longer definitive.

6.1 Compatibility with pre-ANSI CLtL-1 in Allegro CL

The several symbols removed from the language by X3J13 but preserved by Allegro CL for backward compatibility are exported from the cltl1 package. These generally retain their CLtL-1 definitions. We list the symbols exported from the cltl1 package at the end of this section.

Two symbols exported from the flavors package conflict with symbols now exported from the common-lisp package as part of CLOS: defmethod and make-instance. This means that no package can use the flavors package without shadowing these two symbols. See the code at the beginning of flavors.htm.

The following symbols in the cltl1 package have been deleted from standard Common Lisp by X3J13. They (for the most part) maintain their CLtL-1 functionality. You may use the cltl1 package to get backward compatibility but we recommend that you write all new code so that you do not use these symbols and that you modify all existing code as soon as practical. See appendix A for more information on why the symbol was removed from the standard. (An index maps symbols to listed actions. Where possible, the actions give the CLtL-2 page reference where more information is provided.)

Note that special-form-p is in the cltl1 package. That symbol was previously in the common-lisp package but has been replaced in that package with the symbol special-operator-p.

These symbols were in the cltl1 package since release 4.0 and are still there:

applyhook
*applyhook*
*break-on-warnings*
char-bit
char-bits
char-bits-limit
char-control-bit
char-font
char-font-limit
char-hyper-bit
char-meta-bit
char-super-bit
compiler-let
evalhook
*evalhook*
int-char
make-char
set-char-bit
string-char
string-char-p
define-setf-method
get-setf-method-multiple-value
get-setf-method
special-form-p

6.2 Other package changes and compile-time-too behavior

X3J13 made a number of improvements to the package system in order to facilitate portability and to regularize the handling of top-level forms in a file. The function in-package was changed to a macro, and its various keyword arguments were deleted. The macro expansion of in-package is defined to have effect at compile, load, and eval times, but no longer creates a package if it does not exist, nor modifies any existing package. These functionalities are subsumed by the new defpackage macro, along with that of the several other package-manipulating functions. The package name argument to in-package is no longer evaluated. Execution of an in-package form referencing an unknown package or containing optional arguments signals a continuable error.

The variable excl:*cltl1-in-package-compatibility-p* makes in-package work as it did in CLtL-1 Common Lisp. Users porting code from Allegro CL for Windows 3.0.x (which used CLtL-1 semantics in this regard) may find this variable useful. We do recommend modifying the code in the long run, however.

By compile-time-too behavior, we refer to the effect of certain top-level forms in a file being compiled. In CLtL-1, top-level forms which were calling the functions listed below were treated as if they were wrapped in an

(eval-when (compile))

form. That behavior has been changed in the new standard and you must wrap such forms in appropriate eval-when forms if they are to have effect while a file is being compiled. The affected functions are:

proclaim
make-package
shadow
shadowing-import
import
export
unexport
use-package
unuse-package
require

The variable comp:*cltl1-compile-file-toplevel-compatibility-p* can be used to get CLtL-1 compile-time-too behavior when compiling files. Users porting code from Allegro CL for Windows 3.0.x (which used CLtL-1 semantics in this regard) may find this variable useful. We do recommend modifying the code in the long run, however.

6.3 The function data type

X3J13 tightened the definition of the function data type, primarily so generic functions could discriminate on functional arguments. It was necessary that the type represented by the function datatype and functionp predicate be disjoint from all other datatypes. Therefore, in Allegro CL since version 4.2 the only objects that are type function are those returned by the function special form, or by the compile function given a first argument of nil, or by coerce of a lambda expression to type function, or functions loaded from a compiled file. X3J13 specifies that the funcall and apply functions will continue to accept a symbol for the first argument, but a symbol is no longer functionp, nor are lists beginning with lambda, sometimes called lambda expressions. For backward compatibility the funcall and apply functions in Allegro CL will still accept a lambda expression, as is permitted by X3J13, but as required by X3J13 lambda expressions no longer satisfy functionp nor (typep function).

6.4 CLOS and MOP

Previous versions of Allegro CL have used Portable Common Loops (PCL) as a substitute for the Common Lisp Object System (CLOS) which was adopted by X3J13 as a standard part of Common Lisp. The last several versions of PCL worked in most ways the same as CLOS and provided most of the required features. (Some unavoidable divergences of PCL from CLOS derived from the dependence of CLOS on certain other incompatible language changes.)

Since CLOS replaces PCL completely, there has been no attempt to port any version of PCL to Allegro CL 4.3. Doing such a port would be difficult, and would not benefit from the significant speed advantages of the native CLOS implementation in Allegro CL. User code that depends on various details of PCL (especially internals) may have temporary difficulties, but in any case such code will someday need to be brought into conformance with CLOS. In addition to full conformance with CLOS, of course, the other advantage of the native CLOS implementation is its greatly enhanced runtime performance.

CLOS is documented in chapter 28 of CLtL-2. MOP is documented in the book The Art of MetaObject Protocol.

It is possible to trace, disassemble, and compile CLOS methods by name. Here is an example of tracing.

USER(14): (defmethod my-function ((x integer)) (cons x :integer))
#<clos:standard-method my-function ...>
USER(15): (my-function 1)
(1 . :integer)
USER(16): (trace ((method my-function (integer))))
((method my-function (integer)))
USER(17): (my-function 1)
0: ((method my-function (integer)) 1)
0: returned (1 . :integer)
(1 . :integer)
USER(18): (untrace (method my-function (integer)))
((method my-function (integer)))
USER(19): (my-function 1)
(1 . :integer)
USER(20):

Here is how to trace setf, :before, and :after methods (the names and argument types will likely be different in your case, of course):

(trace ((method (setf slot-1) (t baz))))
(trace ((method foo :before (integer))))
(trace ((method foo :after (integer))))

The extra set of parentheses is required to avoid confusion with specifying trace options (they are specified with a list whose car is the function to be traced and whose cdr is a possibly empty list of options). Note that the extra set of parentheses is not used with untrace:

(untrace (method (setf slot-1) (t baz)))
(untrace (method foo :before (integer)))
(untrace (method foo :after (integer)))

A generic function itself can be traced exactly like any other function.

6.5 CLOS and MOP conformance

We list known non-conformances with CLOS and MOP. The basic format is to list the object that is unimplemented or only partially implemented with a brief description of the non-conformance. Unqualified symbols are part of CLOS and are exported from the common-lisp package. Symbols qualified with clos: are part of MOP (they are exported from the clos package).

[Generic function]
clos:class-prototype

Implemented for clos::std-class only. clos::std-class (which is not part of the CLOS standard) is a superclass of funcallable-standard-class and standard-class but is not a superclass of forward-referenced-class, structure-class, and built-in-class. Therefore, methods are defined on the first two classes but not the next three. (This is not actually a non-conformance.)

[Special form]
generic-flet

Removed from spec by X3J13 and not implemented.

[Macro]
generic-function

Removed from spec by X3J13 and not implemented.

[Special form]
generic-labels

Removed from spec by X3J13 and not implemented.

[Generic function]
clos:make-method-lambda

Not implemented.

[Special form]
with-added-methods

Removed from spec by X3J13 and not implemented.

6.6 CLOS optimization

Calls to make-instance where the class-name is a quoted constant and each of the keywords is a constant are transformed by the compiler into calls to constructor functions. A constructor function is a piece of code that is equivalent to the make-instance call except that it is significantly (10 to 100 times) faster.

The optimization is automatic when the call to make-instance is formed in a particular way. In order for an optimized constructor function to be used certain restrictions apply:

  1. The set of keywords must be valid for the call.
  2. Only certain methods must be applicable as defined by the following table:

Generic function

Condition for optimization

make-instance Only system supplied methods are applicable
initialize-instance Only system supplied standard method and user-supplied :after methods are applicable
shared-initialize Only system supplied standard method and user-supplied :after methods are applicable

The calls to make-instance are replaced by calls to the constructor regardless of whether an optimized constructor can be used. The first time the constructor function is called, the restrictions are tested and if they do not apply, an optimized constructor is generated. When the restrictions are not obeyed the constructor calls make-instance. Redefining a class or one of its superclasses or adding/removing a method to one of the generic functions mentioned above causes the constructor function to be recomputed.

7.0 Function specs

A function spec (fspec) is a list that denotes a place to store a function. Function specs are useful for functions that don't otherwise have obvious names. ANSI CL defines Function Names as either symbols or the lists formed by (setf <symbol>) [to denote a writer function to pair with the reader function named by <symbol> which may or may not itself be defined]. Allegro CL extends the Function Name concept by defining function specs, and allows the user to create new kinds of function specs. Some pre-defined function spec names in Allegro CL are :discriminator, :effective-method, method, flet, labels, :internal, :top-level-form, etc.

Function specs are normally kept in an internal form, which allows many of the cons cells in various fspecs to be shared. They are converted to the normal external format usually only when printing, or at other times when parsing the internal form is too complex. Handlers of fspecs must be aware of these internal formats and may use the following functions to access their components:

excl:fspec-first [function]
excl:fspec-second [function]
excl:fspec-third [function]
  Argument: fspec

Each of these functions will work on either an internal or external fspec, and will for an external fspec return the first, second, or third element, respectively (i.e. just like cl:first, cl:second, and cl:third). If the fspec is in internal form, the proper corresponding element is still returned, but without the overhead of first converting to an external fspec.

Users can define there own function specs with def-function-spec-handler.

8.0 Some low-level functionality

Windows: GetWinMainArgs2

The C function GetWinMainArgs2 in the Allegro CL dll (which has a name like acl5xx.dll, where the x's are digits) is used by the IDE to retrieve Windows handle information known by the ACL runtime system. This information may be also be useful for applications written in Lisp. The information returned by this function should be used carefully and non-destructively as the ACL runtime system (i.e. the low-level routines in Allegro CL, unrelated to Allegro Runtime) depends on these handles to exist and behave in predicatable ways.

In order to use this function you must use the foreign function interface to create a Lisp function to call the C function:

(ff:def-foreign-call (GetWinMainArgs2 "GetWinMainArgs2") 
         ((vec (:array :int)) (count :int)) :returning :void) 

Next create a vector of five raw integers for the function to fill in:

(setq myvec (make-array 5 :element-type '(unsigned-byte 32))) 

Now call the function with the vector followed by the number of elements in the vector

(GetWinMainArgs2 myvec (length myvec)) 

The vector now contains the following information

index value 0: The Windows instance handle of the lisp process

index value 1: The previous Windows instance handle (which is always zero).

index value 2: unused

index value 3: The Windows handle of the console window (if there is one).

index value 4: The Windows handle of the splash window. Normally the splash window is gone by the time the application starts up, but the +B command-line argument to lisp.exe can cause the splash window to stay up longer. If this value is non-zero then the application is permitted to call the Windows function DestroyWindow() on it to make the splash window disappear. If this value is zero then the splash window is already gone.

9.0 Compliance with the ANSI specification

The following list describes the (mostly minor or obscure) known non-compliances of Allegro CL with the ANSI spec.

  1. coerce of a sequence, as well as concatenate, map, make-sequence, and merge should signal an error if the new type specifier specifies a different length. Allegro CL presently ignores any length specifier on the new type, never signaling an error even in safe code.
  2. eval and compile are not permitted to copy and/or collapse "like" constants. The compile-file/load cycle is permitted to copy and/or collapse constants. Presently, constants in a file compilation are only collapsed within a single function. Constants are never copied in the evaluator, but Allegro CL's compile violates the no collapsing requirement.
  3. A lexical function or macro definition should prevent setf from using a global setf method. Allegro CL still uses the global definition. (Prior to the introduction of setf functions there was no way a correct program could demonstrate the problem.)
  4. shiftf, and rotatef should support setting multiple values but do not in Allegro CL.
  5. multiple-value-setq of a variable with a symbol-macrolet definition operates on the expansion. Allegro CL's interpreter handles this correctly, but the compiler does not.
  6. Non-local exits from the cleanup forms of an unwind-protect that is in process of unwinding another non-local exit. When a non-local exit (throw, return-from, or go) is being performed, cleanup forms of an intervening unwind-protect form may not transfer to any exit point between itself and the original target exit. Unfortunately, the ANSI spec leaves ambiguous certain details about transferring to exit points outside the original target. Allegro CL currently allows a non-local exit to be usurped by a cleanup form executing another transfer to an intervening exit point. Depending on the ANSI ambiguity, this is either a nonconformance or a extension upon which portable user code should not depend.
  7. The value of *macroexpand- hook* is coerced to type function before being called, and therefore may be a symbol, function, or lambda expression. Allegro CL has always permitted these but macros and symbol macros expanded directly by the compiler (and not indirectly by other macros) don't go through macroexpand-1 and consequently don't invoke *macroexpand-hook*. While the specification is somewhat ambiguous, this should probably be considered a bug.
  8. with-accessors, and with-slots should allow declarations, but in Allegro CL, do not.
  9. The scoping distinctions between pervasive and nonpervasive declarations has been removed. The scope of a declaration always contains the form body along with any "stepper" or "result" forms, but not in general "initialization" forms, e.g. in let binding clauses. If the declaration concerns a binding established by the form, then the declaration applies to the entire scope of the binding. The declaration may therefore include initialization forms in subsequent binding clauses of, for example, let*. Allegro CL does not yet implement this change, retaining CLtL-1 semantics. If made, it will be an incompatible change, although it is unlikely to affect significant amounts of user code.
  10. shadow should accept strings as well as symbols, and also that the symbol name is unconditionally added to the package shadowing list even if a symbol with that name is already accessible in the package. Allegro CL does not yet accept strings as arguments to shadow.
  11. The floating point contagion rules for comparison operations. When float and rational numbers are to be compared, the float is converted to rational as if by the function rational, and then an exact comparison is performed. Allegro CL does not yet implement this change.
  12. Branch cuts for various mathematical functions to specify behavior at floating minus zero. It is difficult on most Allegro CL ports to generate minus zero, although the quantity can certainly be constructed by a foreign function. In any case, Allegro CL's branch cut behavior does not conform around minus zero.
  13. A negative integer :count argument given to the sequence functions remove, remove-if, remove-if-not, delete, delete-if, delete-if-not, substitute, substitute-if, substitute-if- not, nsubstitute, nsubstitute-if, and nsubstitute-if-not should be interpreted the same as a zero count, but in Allegro CL, negative counts are treated as nil.
  14. The behavior of tailp in Allegro CL does not fully conform with regard to its behavior on dotted lists, and whether nil is tailp of any true list.
  15. Allegro CL does not implement the :key keyword argument to assoc-if, assoc-if-not, rassoc-if, and rassoc-if-not.
  16. On an echo-stream, a character should be echoed only the first time it is returned by read-char, and never by peek-char. When a character is returned to the stream with unread-char, it is not unechoed, nor will it be reechoed when it is reread. Allegro CL's new stream implementation does not yet conform. An echo stream always transmits these function calls naively to its component streams.
  17. Allegro CL does not yet support the fourth positional argument to the ~D format directive and a fifth positional argument to the ~R format directive to specify the comma interval.
  18. The ~E format directive always prints a sign for the exponent portion of the number, whereas prin1 prints an exponent sign only if the exponent is negative. In Allegro CL prin1 always prints an exponent sign.
  19. Allegro CL ignores the :newest version specifier of a pathname and always forces it to be nil.
  20. Allegro CL does not implement pathname case, so the :case keyword argument to the make-pathname, pathname-host, pathname-device, pathname-directory, pathname-name, and pathname-type is accepted but ignored.
  21. The definition of compile should permit a compiled function as the optional second argument but does not in Allegro CL.
  22. In Allegro CL, deftype forms are implicitly evaluated at compile time, making the result of the type definition available at compile time, changing the compiling lisp image inappropriately.
  23. Allegro CL does not support cl:documentation for setf functions.
  24. Though calls to the step macro may be compiled in Allegro CL, but compiled code will not correctly expand in the correct lexical environment.
  25. Allegro CL does not allow non-integer time zones.
  26. For macro-like defining forms such as defmacro, macrolet, define-setf-method, deftype, and define-compiler-macro, ths lambda-list default initializer code should run outside the implicit named block established around the definition body but Allegro CL evaluates initializers inside the block.
  27. Allegro CL uses slot name variables as lambda list variables even though an automatically-generated defstruct keyword constructor function should not use and bind as its lambda list variables slot name symbols.
  28. An &environment variable that appears in a macro lambda list should be bound first before any of the other variables (making the binding visible to macroexpansions occurring in initialization forms elsewhere in the lambda list) but Allegro CL binds all variables in normal left-to-right order.
  29. With regard to lambda list congruence between the :arguments keyword argument to define-method-combination and the actual lambda list of a generic function to which the method combination applies, Allegro CL essentially appends an ignored &rest argument to the lambda list, preventing errors from being signaled, but not correctly handling optional/key argument bindings and default value forms.
  30. Allegro CL prints slot names in the keyword package though this behavior is deprecated.
  31. Allegro CL does not permit the type indicator to be omitted for declarations of the form (declare (type foo x)) for any symbol naming a type (Allegro CL does permit it for many predefined types). Thus (declare (foo x)) is not valid in Allegro CL.
  32. Allegro CL does not handle nested dribble's correctly, presently forgeting about the previous dribble, without even closing it.
  33. In Allegro CL, calling a &key function with :allow-other-keys nil signals an error, and it should not.
  34. In Allegro CL, call-next-method with changed arguments does not check that the set of applicable methods has not changed, though it should in safe (safety=3) code.
  35. When butlast is passed a negative second argument, an error should be signaled but Allegro CL never signals this error and silently treats the value as zero.
  36. In Allegro CL, the strings returned by char-name are currently all lower case (the first letter should be capitalized).
  37. Allegro CL implements the second argument to constantp but does not yet implement it properly to differentiate between the compile-time and runtime environments.
  38. In Allegro CL compiler macros are not invoked using *macroexpand-hook* and instead are called using funcall directly. Further, in Allegro CL compiler macros cannot be invoked on forms such as (funcall #'name ...). define-compiler-macro should be responsible for transparently accommodating the argument destructuring for this case but does not in Allegro CL.
  39. For do-symbols, the implicit block nil in the expansion should surround the entire form, not just the body forms, but in Allegro CL wraps the block nil only around the body forms. (do-external-symbols and do-all-symbols are correctly implemented with regard to this point.)
  40. With regard to the documentation function, there should be a documentation type compiler-macro; documentation for a defstruct should be able to be accessed as a class object, just as for defclass; and documentation should support a :documentation clause to defpackage, but does not in Allegro CL.
  41. Allegro CL does not implement setf of values.
  42. typep, subtypep, upgraded-array-element-type, and upgraded-complex-part-type should accept an optional environment argument and deftype should accept an &environment lambda argument in its lambda list, but Allegro CL does not yet implement any of these optional environment arguments, nor does deftype accept the &environment lambda argument.
  43. sxhash should not be sensitive to contents of arrays that are not descended by equal (those other than arrays of type string and bit-vector) but sxhash in Allegro CL is sensitive to the contents of all arrays.
  44. In symbol-macrolet, a type declaration on a symbol-macrolet variable should be equivalent to wrapping every reference to the variable in an appropriate the clause. The expansion should not literally include the the form, but the effect of the type declaration may be effectuated by the compiler by some other means. Allegro CL does not conform, and the expansion of a symbol-macrolet variable with a type declaration includes a the form.
  45. A symbol-macrolet definition of a variable may not shadow a global special declaration of that variable name, or for keyword symbols. symbol-macrolet should signal an error. In Allegro CL, it does not.
  46. A the form should return exactly the values returned by evaluation of its second subform. It should not be an error if more values are returned than the first subform specifies, and if fewer values are returned than the first subform specifies, the missing values are treated as nil for purposes of type checking. In Allegro CL in interpreted code, an error is signalled unless a the form agrees exactly with both the number and types of the returned values. However, in compiled code, it does not check values returned through a the form (although the type declaration may be used for code optimization) and therefore complies.
  47. Allegro signals error (and it should not) if a compiled function is given to compile. Allegro will correctly compile interpreted functions defined in a non-null lexical environment, and will additionally correctly handle references to closed-over variables. However, it imporperly issues a warning when it does so.
  48. A loop macro that includes a named clause generates a block with that name, but should not also generate a block named nil. Allegro CL incorrectly generates the additional block nil.
  49. (SETF (APPLY #'FOO ...) V) should expand to the approximate equivalent (APPLY #'(SETF FOO) V ...) except that the order of evaluation of the original subforms shall be preserved. However, Allegro CL expands setf of apply according to the CLTL-1 specification.
  50. Allegro CL retains certain CLtL2 specifications of the documentation function.
  51. In Allegro CL, butlast and nbutlast improperly signal an error when passed a dotted list argument.
  52. Allegro CL uses the ancient calling convention for defstruct :print-function functions rather than the newer convention used by print-object. Thus, it should be (but is not) possible to use a :print-object clause which receives only two arguments, the object and the stream, omitting the third print level argument passed to a :print-function function. Further, if either of these options (:print-object and :print-function) is specified with no argument, then the printer should perform the default printing behavior for structure objects, which is to use #S syntax, thus providing a limited way of overriding the inheritance of print-object methods, but this is not done in Allegro CL.

Copyright (C) 1998-1999, Franz Inc., Berkeley, CA. All Rights Reserved.