1.2. C Reference

1.2.1. 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:

  • The fields of an object (array, structure, etc) whic is itself alive.

  • A special variable or a constant.

  • The C stack (i.e. automatic variables in a function).

  • Global variables or pointers that have been registered with the garbage collector.

Further details will be provided in the section on Memory Management.

1.2.2. 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.

  • Functions in the Common Lisp ("CL") package are prefixed with the characters "cl_", functions in the System ("SI") package are prefix with "si_", etc, etc.

  • If a function takes only a fixed number of arguments, it is mapped to a C function with also a fixed number of arguments. For instance, COS maps to cl_object cl_cos(cl_object), which takes a single Lisp object and returns a Lisp object of type FLOAT.

  • If the function takes a variable number of arguments, its signature consists on an integer with the number of arguments and zero or more of required arguments and then a C vararg. This is the case of cl_object cl_list(cl_narg narg, ...), which can be invoked without arguments, as in cl_list(0), with one, cl_list(1, a), etc.

  • Functions return at least one value, which is either the first value output by the function, or NIL. The extra values may be retrieved immediately after the function call using the function ecl_nth_value.

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.

1.2.3. 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

  • Common Lisp macros such as with-open-files.

  • Common Lisp special forms, such as cond

  • Common Lisp generic functions, which cannot be written in C because of their dynamical dispatch and automatic redefinition properties.

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.