Features of Cecil
Cecil is a purely object-oriented, type-safe, garbage-collected
language intended to support rapid construction of high-quality, extensible
software. Cecil includes the following features (here
are some resources):
Cecil has multimethods, which generalize singly dispatched receiver-oriented
languages to allow dynamic dispatching on any subset of a method's arguments.
Dispatched arguments are treated symmetrically, unlike Common Lisp where
earlier arguments are more important than later arguments.
Cecil has a classless object model. Objects have methods attached directly
to them, without needing a separate class to hold their format & behavior.
One-of-a-kind objects with their own behavior (e.g. true, false, nil, and
other enumerated constants) are easy to define.
Cecil has first-class lexically-nested anonymous functions, a la Smalltalk
blocks, Scheme lambdas, and ML functions. Function values are heavily used
in Cecil code for user-defined control structures, iterators, exception
handlers, typecase-like constructs, and more.
Cecil has both immutable (the default) and mutable versions of local, global,
and instance variables (called fields in Cecil). Immutable variables support
clearer, more understandable code. Initial values of variables are specified
at the point of declaration, except that for fields initial values can
be specified when the containing object is created.
Cecil accesses both fields (instance variables) and methods via dynamically
dispatched messages. Each field declaration implicitly generates a get
and (if mutable) a set accessor method providing the sole means for reading
and writing the field's contents. By accessing fields and methods uniformly,
implementors can easily change between storing and computing some value
w/o modifying clients, and methods can be overridden with fields and vice-versa.
Cecil has predicate objects, which allow virtual "subclasses" to be defined
carrying specialized methods that override their parent's methods whenever
some boolean predicate over the object is true. In this way, inheritance
can be used to model time-varying and/or state-dependent properties of
objects just like permanent properties of objects.
Cecil supports multiple inheritance. The inheritance graph is treated as
a partial order, inducing a corresponding partial order on methods attached
to those objects. This design results in the simple rule that a method
attached to a child overrides any method attached to an ancestor.
Cecil's object declarations do not "contain" their method, field, or even
parent declarations. Instead, all these attributes of objects are declared
externally, allowing clients to add methods, fields, and even parents of
existing objects separately from their original definition.
Cecil supports a polymorphic static type system. Types and subtyping is
semantically distinct and independent from from objects and inheritance,
although syntactic sugar makes declaration of parallel subtyping and inheritance
easy. Any declaration can be polymorphic over some set of type parameters,
and constraints can be placed on these type parameters to limit the set
of legal instantiating types to those that satisfy needed properties; Cecil's
constraint-based bounds subsume (F-)bounded polymorphism and where clauses.
Cecil's type declarations are optional. Where type declarations are present,
static type checking ensures that the type declarations are internally
consistent. Where omitted, dynamic type checking guarantees run-time type
History of Cecil
The initial Cecil design effort was started in early 1991. The first Cecil
interpreter and typechecker implementation, written in Self, was done over
1992 and 1993. In 1993, a translator from Cecil to C was added to the
interpreter, making the first Cecil compiler. In 1994, a larger Cecil
optimizing compiler, this time written in Cecil, was begun; this compiler
eventually evolved into the Vortex optimizing compiler.
Some resources for Cecil