Announcement of ECL v0.9b
ECL stands for Embeddable Common-Lisp. The ECL project is an effort to
modernize Giusseppe Attardi's ECL (ECoLisp) environment to produce an
implementation of the Common-Lisp language which complies to the ANSI
X3J13 definition of the language.
ECL is currently hosted at SourceForge. The home page of the project
is http://ecls.sourceforge.net, and in it you will find source code
releases, a CVS tree and an up to date documentation.
Notes for this release
Two new platforms have been added: Sparc/Solaris and Alpha/Linux. It
should be rather straightforward to port ECL to any platform with any
word size. Furthermore, ECL should now be able to cross-compile itself:
just invoke "configure" with a "--host=..." argument, and watch the
output to get instructions on how to do it.
ECL is now heading not only for ANSI compatibility but also for a full
implementation of the AMOP. As first improvements, ECL this release
implements the initialization and reinitialization protocols for classes,
as well as method combinations. A lot to be done, but we are on the way.
We are also working on the FFI, and as starters a new special form has been
implemented, called C-INLINE, which allows to insert C code wherever a lisp
form is valid and provides a sound layer for a future implementation of the
UFFI 1 standard.
* Supported platforms:
- Solaris 32 bits.
- Linux/Alpha 64 bits.
* Errors fixed:
- DPP now properly handles &allow_other_keys.
- NIL could not be the name of a slot in a struct.
- (/ 0 0) should signal an error.
- FORMAT control ~C now works as expected.
- (SETF DOCUMENTATION) did not work on classes.
- The option :DOCUMENTATION produced an error in DEFINE-CONDITION.
- ENSURE-DIRECTORIES-EXIST was broken.
- EQL specializers were compared to the arguments using EQ instead
- Method hash tables could grow indefinitely. Now they are limited
to 512 elements.
* System design:
- The bytecodes compiler now works with character arrays. Bytecodes
are thus 8 bits large, while their arguments are 16 bits large.
Lisp objects referenced in the code are kept in a separate array
to simplify garbage collection. This strategy limits the size of
bytecode objects to about 32000 bytes and about 32000 constants,
but reduces the use of memory by about 25%.
- Macros are implemented in C as functions with two arguments.
Argument checking is thus left to funcall() and apply(), saving
- AND, OR and WHEN are now just macros, without any special
treatment in the bytecodes compiler.
- To support a large number of arguments, when a function receives
more than 64 values they get stored in the stack of the lisp
interpreter, and general purpose routines are used to handle
them (cl_va_list, cl_va_arg, etc). Now, for functions which can
only receive up to 32 values (i.e. functions without &rest,
&key, and thess than 32 arguments including optionals), ECL
avoids using this overhead by using directly va_list and va_arg.
* Visible changes:
- New special form C-INLINE, allows inserting C/C++ code in any
place where a lisp form is allowed.
- New lisp object type, t_foreign, for user-allocated or "foreign"
data; plus routines to simulate the UFFI foreign functions
- New function SI::FILE-KIND (based on lstat() and stat()) returns
either :DIRECTORY, :FILE, :LINK, :SPECIAL, or NIL (= Non
existent), for a given file name.
- Bytecode-compiled functions now print as
#<bytecompiled-function... just to remark that, according to ANSI,
these functions are not interpreted (i.e. there are no run-time
dependencies on macros left).
- Formerly, the process of inlining a call to a function would be
done only once the C code is written. For instance, if the
(FUNCALL (LAMBDA (X) (COS X)) 1.0)
it would only decide to do the inlining during the second phase of
the compilation process. That meant extremely complicated and easy
to break code in the compiler. The new engine does the inlining of
these forms during the first phase, in which Lisp is translated to
an intermediate representation. For instance, the previous form
is translated to
(LET ((X 1.0)) (COS X))
and here optimizations are much easier.
- The optimizers for the MAPCAR, MAPCAN, etc, were broken. They will
be replaced with compiler macro functions, which are easier to
- CLEAR-INPUT now works with interactive streams (*STANDARD-INPUT, etc).
- On systems which support it, LISTEN-STREAM is now implemented
using select(). This means it now works on sockets as well.
- LOAD now accepts a fourth keyword argument, :SEARCH-LIST, which
is a list of directories where LOAD should try to find the file.
The value of SEARCH-LIST defaults to SI::*LOAD-SEARCH-LIST*. If
the file is not found using SEARCH-LIST, then the current
directory is tried.
- Two implementations of FORMAT are supplied: the old one written in
C and a port of the code in CMUCL. The last one is selected with
the flag --with-cmuformat.
- ECL extension AUTOLOAD implemented. An example
(autoload "sys:cmp" 'compile 'compile-file 'disassemble)
* ANSI compatibility:
- DIRECTORY now understands :WILD, :UP, :WILD-INFERIORS, and, as an
extension, other masks within the pathname ("/foo*/**/d*d.l?sp").
It also accepts and ignores all keyword arguments.
- LOAD no longer binds *STANDARD-INPUT* to the file being read. That
was wrong, AFAIK.
- An important problem in DEFSTRUCT has been solved: when :CONC-NAME
is NIL, it may happen that a second definition of a function
overwrites the reader of a slot. For instance
(defstruct (foo (:conc-name nil)) slot-a)
(defstruct (faa (:include foo) (:conc-name nil)))
would produce an accessor SLOT-A which only works for structures
of type FAA:
(SLOT-A (MAKE-FAA)) => NIL
(SLOT-A (MAKE-FOO)) => Error
- The set of valid keyword arguments for a method depends on the
applicable methods for each specific call. Thus, the associated
LAMBDA forms need not check the consistency of arguments
themselves, and may be declared with &allow-other-keys. With the
new code, this is valid:
(defmethod foo (&key b) ...)
(defmethod foo :after (&key x) ...)
but an invalid call (FOO :C 2) is undetected.
- All streams have from now on element type (UNSIGNED-BYTE 8).
READ-CHAR and WRITE-CHAR work on any stream, though, as do
READ-BYTE and WRITE-BYTE.
- READ/WRITE-SEQUENCE implemented.
- OPEN now accepts the parameter :EXTERNAL-FORMAT, which can only be
:DEFAULT, as ECL does not support the notion of external formats
(all streams have element type (UNSIGNED-BYTE 8)).
- Method combinations are now fully supported.
- DEFGENERIC now accepts the :METHOD-COMBINATION and :METHOD options.
- The initialization and finalization protocol from the AMOP have
been almost fully implemented. Still missing are the class
redefinition and instance obsolence protocols.
- FORMATTER has been implemented, and ERROR/CERROR now accept as
"datum" the functions produced by FORMATTER.
- FORMAT has been ported from CMUCL, to have a second implementation
which is more easy to maintain, and less error-prone.