ECL is implemented using either a C or a C++ compiler. This is not a limiting factor, but imposes some constraints on how these languages are used to implement functions, multiple values, closures, etc. In particular, while C functions can be called with a variable number of arguments, there is no facility to check how many values were actually passed. This forces us to have two types of functions in ECL
Functions that take a fixed number of arguments have a simple C signature, with all arguments being properly declared, as in cl_object cl_not(cl_object arg1)
.
Functions with a variable number of arguments, such as those acception &optional, &rest or &key arguments, must take as first argument the number of remaining ones, as in cl_object cl_list(cl_narg narg, ...)
. Here narg
is the number of supplied arguments.
The previous conventions set some burden on the C programmer that calls ECL, for she must know the type of function that is being called and supply the right number of arguments. This burden disappears for Common Lisp programmers, though.
As an example let us assume that the user wants to invoke two functions which are part of the ANSI standard and thus are exported with a C name. The first example is cl_cos
, which takes just one argument and has a signature cl_object cl_cos(cl_object)
.
#include <math.h> ... cl_object angle = ecl_make_double_float(M_PI); cl_object c = cl_cos(angle); printf("\nThe cosine of PI is %g\n", ecl_double_float(c));
The second example also involves some Mathematics, but now we are going to use the C function corresponding to +. As described in the C dictionary, the C name for the plus operator is cl_P
and has a signature cl_object cl_P(cl_narg narg,...)
. Our example now reads as follows
cl_object one = ecl_make_fixnum(1); cl_object two = cl_P(2, one, one); cl_object three = cl_P(2, one, one, one); printf("\n1 + 1 is %d\n", ecl_fixnum(two)); printf("\n1 + 1 + 1 is %d\n", ecl_fixnum(three));
Note that most Common Lisp functions will not have a C name. In this case one must use the symbol that names them to actually call the functions, using cl_funcall
or cl_apply
. The previous examples may thus be rewritten as follows
/* Symbol + in package CL */ cl_object plus = ecl_make_symbol("+","CL"); cl_object one = ecl_make_fixnum(1); cl_object two = cl_funcall(3, plus, one, one); cl_object three = cl_funcall(4, plus, one, one, one); printf("\n1 + 1 is %d\n", ecl_fixnum(two)); printf("\n1 + 1 + 1 is %d\n", ecl_fixnum(three));
Another restriction of C and C++ is that functions can only take a limited number of arguments. In order to cope with this problem, ECL uses an internal stack to pass any argument above a hardcoded limit, ECL_C_CALL_ARGUMENTS_LIMIT
, which is as of this writing 63. The use of this stack is transparently handled by the Common Lisp functions, such as apply, funcall and their C equivalents, and also by a set of macros, cl_va_arg
, which can be used for coding functions that take an arbitrary name of arguments.