Next: , Previous: , Up: Top   [Contents][Index]

3 Standards


Next: , Up: Standards   [Contents][Index]

3.1 Overview

3.1.1 Reading this manual

Common Lisp users

Embeddable Common Lisp supports all Common-Lisp data types exactly as defined in the [see ANSI]. All functions and macros are expected to behave as described in that document and in the HyperSpec [see HyperSpec] which is the online version of [see ANSI]. In other words, the Standard is the basic reference for Common Lisp and also for Embeddable Common Lisp, and this part of the manual just complements it, describing implementation-specific features such as:

In order to aid in locating these differences, this first part of the manual copies the structure of the ANSI Common-Lisp standard, having the same number of chapters, each one with a set of sections documenting the implementation-specific details.

C/C++ programmers

The second goal of this document is to provide a reference for C programmers that want to create, manipulate and operate with Common Lisp programs at a lower level, or simply embedding Embeddable Common Lisp as a library.

The C/C++ reference evolves in parallel with the Common Lisp one, in the form of one section with the name "C Reference" for each chapter of the ANSI Common-Lisp standard. Much of what is presented in those sections is redundant with the Common Lisp specification. In particular, there is a one-to-one mapping between types and functions which should be obvious given the rules explained in the next section C Reference.

We must remark that the reference in this part of the manual is not enough to know how to embed Embeddable Common Lisp in a program. In practice the user or developer will also have to learn how to build programs (System building), interface with foreign libraries (Foreign Function Interface), manage memory (Memory Management), etc. These concepts are explained in a different (Embedding ECL) part of the book.

3.1.2 C Reference

One type for everything: cl_object

ECL is designed around the basic principle that Common Lisp already provides everything that a programmer could need, orienting itself around the creation and manipulation of Common Lisp objects: conses, arrays, strings, characters, ... When embedding ECL there should be no need to use other C/C++ types, except when interfacing data to and from those other languages.

All Common Lisp objects are represented internally through the same C type, cl_object, which is either a pointer to a union type or an integer, depending on the situation. While the inner guts of this type are exposed through various headers, the user should never rely on these details but rather use the macros and functions that are listed in this manual.

There are two types of Common Lisp objects: immediate and memory allocated ones. Immediate types fit in the bits of the cl_object word, and do not require the garbage collector to be created. The list of such types may depend on the platform, but it includes at least the fixnum and character types.

Memory allocated types on the other hand require the use of the garbage collector to be created. ECL abstracts this from the user providing enough constructors, either in the form of Common Lisp functions (cl_make_array(), cl_complex(),...), or in the form of C/C++ constructors (ecl_make_symbol(), etc).

Memory allocated types must always be kept alive so that the garbage collector does not reclaim them. This involves referencing the object from one of the places that the collector scans:

For memory allocation details See Memory Management. For object implementation details See Manipulating Lisp objects.

Naming conventions

As explained in the introduction, each of the chapters in the Common Lisp standard can also be implemented using C functions and types. The mapping between both languages is done using a small set of rules described below.

In addition to the Common Lisp core functions (cl_*), there exist functions which are devoted only to C/C++ programming, with tasks such as coercion of objects to and from C types, optimized functions, inlined macroexpansions, etc. These functions and macros typically carry the prefix ecl_ or ECL_ and only return one value, if any.

Most (if not all) Common Lisp functions and constructs available from C/C++ are available in “ANSI Dictionary” sections which are part of the [Standards] entries.

Only in Common Lisp

Some parts of the language are not available as C functions, even though they can be used in Common Lisp programs. These parts are either marked in the “ANSI Dictionary” sections using the tag Only in Common Lisp, or they are simply not mentioned (macros and special constructs). This typically happens with non-translatable constructs such as

In most of those cases there exist straightforward alternatives using the constructs and functions in ECL. For example, unwind-protect can be implemented using a C macro which is provided by ECL

cl_env_ptr env = ecl_process_env();
CL_UNWIND_PROTECT_BEGIN(env) {
    /* protected code goes here */
} CL_UNWIND_PROTECT_EXIT {
    /* exit code goes here */
} CL_UNWIND_PROTECT_END;

Common Lisp generic functions can be directly accessed using funcall or apply and the function name, as shown in the code below

cl_object name = ecl_make_symbol("MY-GENERIC-FUNCTION","CL-USER");
cl_object output = cl_funcall(2, name, argument);

Identifying these alternatives requires some knowledge of Common Lisp, which is why it is recommended to approach the embeddable components in ECL only when there is some familiarity with the language.


Next: , Previous: , Up: Standards   [Contents][Index]

3.2 Syntax


Next: , Previous: , Up: Standards   [Contents][Index]

3.3 Evaluation and compilation

3.3.1 Compiler declaration OPTIMIZE

The OPTIMIZE declaration includes three concepts: DEBUG, SPEED, SAFETY and SPACE. Each of these declarations can take one of the integer values 0, 1, 2 and 3. According to these values, the implementation may decide how to compie or interpret a given lisp form.

ECL currently does not use all these declarations, but some of them definitely affect the speed and behavior of compiled functions. For instance, the DEBUG declaration, as shown in Table 3.1, the value of debugging is zero, the function will not appear in the debugger and, if redefined, some functions might not see the redefinition.

Behavior0123
Compiled functions in the same source file are called directlyYYNN
Compiled function appears in debugger backtraceNNYY
All functions get a global entry (SI:C-LOCAL is ignored)NNYY

Table 3.1: Behavior for different levels of DEBUG

A bit more critical is the value of SAFETY because as shown in Table 3.2, it may affect the safety checks generated by the compiler. In particular, in some circumstances the compiler may assume that the arguments to a function are properly typed. For instance, if you compile with a low value of SAFETY, and invoke RPLACA, the consequences are unspecified.

Behavior0123
The compiler generates type checks for the arguments of a lambda form, thus enforcing any type declaration written by the user.NYYY
The value of an expression or a variable declared by the user is assumed to be right.YYNN
We believe type declarations and type inference and, if the type of a form is inferred to be right for a function, slot accessor, etc, this may be inlined. Affects functions like CAR, CDR, etcYYNN
We believe types defined before compiling a file not change before the compiled code is loaded.YYNN
Arguments in a lisp form are assumed to have the appropriate types so that the form will not fail.YNNN
The slots or fields in a lisp object are accessed directly without type checks even if the type of the object could not be inferred (see line above). Affects functions like PATHNAME-TYPE, CAR, REST, etc.YNNN

Table 3.2: Behavior for different levels of SAFETY

3.3.2 C Reference

C/C++ identifier: cl_object cl_env_ptr ()

ECL stores information about each thread on a dedicated structure, which is the process environment. A pointer to this structure can be retrieved using the function or macro above. This pointer can be used for a variety of tasks, such as defining special variable bindings, controlling interrupts, retrieving function output values, etc.

3.3.3 ANSI Dictionary

Lisp symbolC/C++ function
compileOnly in Common Lisp
evalcl_object cl_eval (cl_object form)
compiler-macro-functionOnly in Common Lisp
macro-functioncl_object cl_macro_function(cl_narg narg, cl_object symbol, ...)
macroexpandcl_object cl_macroexpand(cl_narg narg, cl_object form, ...)
macroexpand-1cl_object cl_macroexpand_1(cl_narg narg, cl_object form, ...)
proclaimOnly in Common Lisp
special-operator-pcl_object cl_special_operator_p(cl_object form)
constantpcl_object cl_constantp(cl_narg narg, cl_object form, ...)

Next: , Previous: , Up: Standards   [Contents][Index]

3.4 Types and classes

ECL defines the following additional built-in classes in the CL package:

3.4.1 C Reference

3.4.2 ANSI Dictionary

Lisp symbolC/C++ function
coercecl_object cl_coerce (cl_object object, cl_object result-type)
subtypepcl_object cl_subtypep (cl_narg narg, cl_object type1, cl_object type2, ...)
type-ofcl_object cl_type-of (cl_object object)
typepcl_object cl_typep (cl_narg narg, cl_object object, cl_object type_specifier, ...)
type-error-datumOnly in Common Lisp
type-error-expected-typeOnly in Common Lisp

Next: , Previous: , Up: Standards   [Contents][Index]

3.5 Data and control flow


Next: , Up: Data and control flow   [Contents][Index]

3.5.1 Shadowed bindings

ANSI doesn’t specify what should happen if any of the LET, FLET and LABELS special operators contain many bindings sharing the same name. Because the behavior varies between the implementations and the programmer can’t rely on the spec ECL signals an error if such situation occur.

Moreover, while ANSI defines lambda list parameters in the terms of LET*, when used in function context programmer can’t provide an initialization forms for required parameters. If required parameters share the same name the error is signalled.

Described behavior is present in ECL since version 16.0.0. Previously the LET operator were using first binding. Both FLET and LABELS were signalling an error if C compiler was used and used the last binding as a visible one when the byte compiler was used.


Next: , Previous: , Up: Data and control flow   [Contents][Index]

3.5.2 Minimal compilation

Former versions of ECL, as well as many other lisps, used linked lists to represent code. Executing code thus meant traversing these lists and performing code transformations, such as macro expansion, every time that a statement was to be executed. The result was a slow and memory hungry interpreter.

Beginning with version 0.3, ECL was shipped with a bytecodes compiler and interpreter which circumvent the limitations of linked lists. When you enter code at the lisp prompt, or when you load a source file, ECL begins a process known as minimal compilation. Barely this process consists on parsing each form, macroexpanding it and translating it into an intermediate language made of bytecodes.

The bytecodes compiler is implemented in src/c/compiler.d. The main entry point is the lisp function si::make-lambda, which takes a name for the function and the body of the lambda lists, and produces a lisp object that can be invoked. For instance,

> (defvar fun (si::make-lambda 'f '((x) (1+ x))))
*FUN*
> (funcall fun 2)
3

ECL can only execute bytecodes. When a list is passed to EVAL it must be first compiled to bytecodes and, if the process succeeds, the resulting bytecodes are passed to the interpreter. Similarly, every time a function object is created, such as in DEFUN or DEFMACRO, the compiler processes the lambda form to produce a suitable bytecodes object.

The fact that ECL performs this eager compilation means that changes on a macro are not immediately seen in code which was already compiled. This has subtle implications. Take the following code:

> (defmacro f (a b) `(+ ,a ,b))
F
> (defun g (x y) (f x y))
G
> (g 1 2)
3
> (defmacro f (a b) `(- ,a ,b))
F
> (g 1 2)
3

The last statement always outputs 3 while in former implementations based on simple list traversal it would produce -1.


Previous: , Up: Data and control flow   [Contents][Index]

3.5.3 Function types

Functions in ECL can be of two types: they are either compiled to bytecodes or they have been compiled to machine code using a lisp to C translator and a C compiler. To the first category belong function loaded from lisp source files or entered at the toplevel. To the second category belong all functions in the ECL core environment and functions in files processed by compile or compile-file.

The output of (symbol-function fun) is one of the following:

ECL usually drops the source code of a function unless the global variable si:*keep-definitions* was true when the function was translated into bytecodes. Therefore, if you wish to use compile and disassemble on defined functions, you should issue (setq si:*keep-definitions* t) at the beginning of your session.

SI: *keep-definitions*

If set to T ECL will preserve the compiled function source code for disassembly and recompilation.

In Table 3.3 we list all Common Lisp values related to the limits of functions.

call-arguments-limit65536
lambda-parameters-limitcall-arguments-limit
multiple-values-limit64
lambda-list-keywords(&optional &rest &key &allow-other-keys &aux &whole &environment &body)

Table 3.3: Function related constants


Next: , Previous: , Up: Standards   [Contents][Index]

3.6 Iteration


Next: , Previous: , Up: Standards   [Contents][Index]

3.7 Objects


Next: , Previous: , Up: Standards   [Contents][Index]

3.8 Structures


Next: , Previous: , Up: Standards   [Contents][Index]

3.9 Conditions


Next: , Previous: , Up: Standards   [Contents][Index]

3.10 Symbols


Next: , Previous: , Up: Standards   [Contents][Index]

3.11 Packages


Next: , Previous: , Up: Standards   [Contents][Index]

3.12 Numbers


Next: , Previous: , Up: Standards   [Contents][Index]

3.13 Characters


Next: , Previous: , Up: Standards   [Contents][Index]

3.14 Conses


Next: , Previous: , Up: Standards   [Contents][Index]

3.15 Arrays


Next: , Previous: , Up: Standards   [Contents][Index]

3.16 Strings


Next: , Previous: , Up: Standards   [Contents][Index]

3.17 Sequences


Next: , Previous: , Up: Standards   [Contents][Index]

3.18 Hash tables


Next: , Previous: , Up: Standards   [Contents][Index]

3.19 Filenames


Next: , Previous: , Up: Standards   [Contents][Index]

3.20 Files


Next: , Previous: , Up: Standards   [Contents][Index]

3.21 Streams


Next: , Previous: , Up: Standards   [Contents][Index]

3.22 Printer


Next: , Previous: , Up: Standards   [Contents][Index]

3.23 Reader


Next: , Previous: , Up: Standards   [Contents][Index]

3.24 System construction


Next: , Previous: , Up: Standards   [Contents][Index]

3.25 Environment


Previous: , Up: Standards   [Contents][Index]

3.26 Glossary


Previous: , Up: Standards   [Contents][Index]