Cecil

0. Intended Use

Cecil is an object-oriented language intended for both exploratory andproduction programming.

1. Basic Concepts

Cecil is based on a pure object model. All data are objects, and objectsare manipulated soley by passing messages. Cecil uses a classless (prototype-based)object model, in which (conceptually) self-sufficient objects implementdata abstractions, and objects inherit directly from other objects (delegation)to share code. Cecil also supports a general form of dynamic binding basedon multiple dispatching. Cecil attempts to combine multi-methods with traditionalobject-oriented language concepts, such as encapsulation and static typechecking.

2. Objects

2.1 operations

Cecil supports a generalized object model, in which objects can be madeto behave like those in a classical object model if desired. See entryunder 2.5 methods.

2.2 requests

2.3 messages

All computation in Cecil is accomplished by sending messages to objects.Method lookup in response to a message is constrained by argument specializersdefined for the methods (see 2.5 methods). Informally, a messageis considered as being sent to all its argument objects. When a messageis sent, the system finds all methods with the same name and number ofarguments as the message. The system then eliminates from considerationthose methods whose argument specializers are too restrictive to applyto the actual parameters passed in the call (if no methods are applicableafter this step, a "message not understood" error is reported).Of the remaining applicable methods, the system locates the one whose argumentspecializers are most specific, and invokes that method to respond to themessage. If no single method is most specific, a "message ambiguous"error is reported (i.e., Cecil does not attempt to resolve ambiguity itself).[Cha92]

2.4 specification of behavioral semantics

2.5 methods

In Cecil, a method declaration has the general form

There is no implicit selfformal argument; all formal arguments of a method are listed explicitly.A method specifies the kinds of arguments for which its code is designedto work. For each formal argument of a method, the programmer may specifythat the method is applicable only to actual arguments that are implementedor represented in a particular way, i.e., that are equal to or inheritfrom a particular object, called an argument specializer (recallthat Cecil is prototype-based (classless), and thus objects inherit fromother objects, rather than classes inheriting from classes). In the declarationabove, the obji representargument specializers.

As indicated by the syntax above, argument specializers are distinctfrom type declarations. Argument specializers restrict the allowed implementationsof actual arguments, and are used as part of method lookup to locate asuitable method to handle a message send (see entry under 2.3 messages).On the other hand, type declarations require that certain operations besupported by argument objects, but place no constraints on how those operationsare implemented. Type declarations have no effect on method lookup.

Argument specializers are optional, and zero, one, or several (or all)of a method's arguments may be specialized. If zero arguments are specialized,the method acts like a conventional undispatched function or procedure.If only the first argument is specialized, the method acts like a normalsingly-dispatched method in a language such as Smalltalk. If several argumentsare specialized, the method is a multi-method (a method selectedon the basis of more than one argument) as supported in a language suchas CLOS. Callers which send a particular message to a group of argumentsneed not be aware of the collection of methods that might handle the messageor which arguments of the methods are specialized, if any. Methods maybe overloaded, i.e., there may be many methods with the same name, as longas the methods with the same name and number of arguments differ in theirargument specializers. Methods with different numbers of arguments areindependent; the system considers the number of arguments to effectivelybe part of the method's name.

Methods and objects are effectively connected through the methods' argumentspecializers. The methods in the system with the same name have no explicitconnection or relationship beyond the programmer's intentions. This isin contrast to the approach used, e.g., in CLOS, of linking all multi-methodswith the same name into a single generic function object. In Cecil, methodsare closely associated with their specializing objects (i.e., the objectswhose implementations include the methods), and only weakly connected witheach other. This approach to multi-methods permits viewing objects andtheir connected methods as a unit which implements a data abstraction;the methods defined for a particular object are always directly accessiblefrom the object. The mental image required is that of a graph of relationshipsamong objects and methods. Consequently, Cecil requires a graphical interactiveprogramming environment that can display these relationships and dynamically-varyingviews of them. For example, this environment could show objects on thescreen, with their associated multi-methods "contained" withinthe objects. The same multi-method could be viewed from each of its specializingobjects.

The following group of object declaration skeletons illustrate a simple(instance) inheritance hierarchy, together with some differently-specializedmethod definitions [Cha93]. These illustrate how methods implementing the"+" (addition)operator can be specialized to work on different combinations of argumentimplementations.

object int inherits number;
method +(@int, @int) {abstract}
[* children must provideimplementation]


object small_int inherits int, prim_int;
method +(x@small_int, y@small_int) {
*code of method*}
method +(x@small_int, y@big_int) {
*code of method*}

object big_int inherits int;
method +(x@big_int, y@big_int) {
*code of method*}
method +(x@big_int, y@small_int) {
*code of method*}

object zero inherits int;
method +(@zero, x) {x}
[*zero plus x is x]
method +(x, @zero) {x}
method +(z@zero, @zero) {z}

2.6 state

In Cecil a method declaration whose body is the keyword fielddefines a pair of accessor methods which share hidden mutable state. Theget accessor method (whose name is the same as the declared field)takes a single argument, specialized on the object "containing"the field, and returns the contents of the field. The set accessormethod (whose name is set_ followedby the declared field name) takes two arguments: one specialized on theobject containing the field and the second unspecialized. When invoked,the set accessor mutates the contents of the field to refer to its secondargument; set accessors do not return results. Specializing the accessormethods on the object containing the field establishes the link betweenthe accessor methods and the object, allowing the accessor methods to beconsidered part of the object's implementation. See entry under 5. Encapsulation.

2.7 object lifetime

New objects are created either through object declarations, orby evaluating object constructor expressions. An object declarationhas the form:

where <relation>denotes isa, inherits,or subtypes specificationsdescribing the parents and/or supertypes (respectively) of the new object.The form of an object constructor expression is the same except that noname is specified. Object constructor expressions are analogous to objectcreation operations found in class-based languages. Note that only fieldsare specified in object constructors; methods are defined in separate expressionsto allow them to be associated with multiple objects through their specializers(see entry under 2.5 methods). Objects are garbage collected whenthey are no longer referenced by other objects.

2.8 behavior/state grouping

Cecil implements a generalized object model. In Cecil, objects and methodsconceptually form a graph structure, with the object/method relationshipsbeing established by method specializers. See entry under 2.5 methods.

2.9 communication model

3. Binding

See entry under 2.3 messages.

4. Polymorphism

5. Encapsulation

Cecil supports a form of object encapsulation which merges aspects of"classical" object models with its own "generalized"object model capabilities. Fields and methods can be prefixed with publicor private declarationsthat effectively define an object's interface.

Intuitively, a private method is internal to the data abstraction implementation(s)of which it is a part, and only other methods also within the same implementation(s)can invoke that private method. More precisely, a sending method S is grantedaccess to a private method M only if S is considered part of the implementationof which M is also a part. A method is considered part of the implementationof an object if at least one of its formal arguments is specialized onthe object. Additionally, to deal with situations involving children accessingor overriding private methods which they inherit from their ancestors,a method is considered part of the implementation of an object if at leastone of its formal arguments is specialized on an ancestor or descendantof the object. A method that dispatches on more than one argument is consideredpart of the implementation of all dispatched arguments, and so is grantedprivileged access to each of them. (Note that, as described in the entryunder 2.6 state, fields resolve to pairs of methods, so access toboth state and behavior is covered by these rules.)

6. Identity, Equality, Copy

In Cecil, each object has unique identity.

7. Types and Classes

Cecil supports a static type system which is layered on top of a dynamically-typedcore language. Cecil's type system is descriptive rather than prescriptive.The semantics of a Cecil program are determined completely by the dynamically-typedcore of the program. Type declarations serve only as documentation andpartial redundancy checks, and they do not influence the execution behaviorof programs. It is intended that type annotations could be added to a programas it progresses from development to production use.

A type in Cecil is an abstraction of an object. A type representsa machine-checkable interface and an implied but unchecked behavioral specification,and all objects which conform to the type must support the type'sinterface and promise to satisfy the behavioral specification. One typemay claim to be a subtype of another, in which case all objectswhich conform to the subtype are guaranteed also to conform to the supertype.The type checker verifies that the interface of the subtype conforms tothe interface of the supertype, but the system must accept the programmer'spromise that the subtype satisfies the implied behavioral specificationof the supertype. Subtyping is explicit in Cecil just so that these impliedbehavioral specifications can be indicated.

A signature in Cecil is an abstraction of a method, specifyingboth an interface (a name, a sequence of argument types, and a result type)and an implied but uncheckable behavioral specification. A set of signaturesforms the interface of a type. A signature is viewed as associated witheach of its argument types, not just the first, much as a multi-methodin Cecil is associated with each of its argument specializers.

Cecil separates subtyping from code inheritance. However, since in mostcases the subtyping graphs and the inheritance graphs are parallel, inCecil both graphs are specified simultaneously with a single set of objectand method declarations. An objectdeclaration constructs both a new object in the inheritance graph and anew type in the type lattice (similarly, a method implies the existenceof a corresponding signature). See entry under 2.6 object lifetime.The new object in the inheritance (implementation) graph is a direct childof the objects named in the inheritsand isa clauses, if any.The new node in the type lattice is a direct subtype of each of the typesnamed in the subtypesand isa clauses, if any.Finally, the new object is declared to conform to the new type. Objectconstructor expressions similarly generate both objects and types, butthese objects and types are anonymous (have no names).

Each of the names included in an isaclause is interpreted both as an object (when constructing the inheritancegraph) and as a type (when constructing the type lattice), and so providesa shorthand for declaring both inheritsand subtypes clauses withthe same name. This is designed to make it easy to specify the inheritanceand subtyping properties of an object/type pair for the common case wherecode inheritance and subtyping are parallel. It is expected that in mostprograms only isa declarationswill be used; inheritsand subtypes declarationsare intended for the cases where distinctions between inheritance and subtypingmust be specified.

Some objects are not intended to correspond to first-class types used,e.g., in variable declarations. To support this distinction, an objectdeclaration that is intended to generate a first-class namable type usesthe keyword type ratherthan object in the objectdeclaration. Both objectand type declarationscreate both an object and a type, but the type created as part of an objectdeclaration is an internal type that cannot normally be named by the program.

At present, Cecil does not provide programmers the ability to definetypes or signatures separately from objects and methods. If only a typeor signature is needed, then an abstracttype object declaration or an abstractmethod can be used.

Subtyping and conformance in Cecil is explicit, in that the programmermust explicitly declare that an object conforms to a type and that a typeis a subtype of another type. These explcit declarations are verified aspart of type checking to ensure that they preserve the required propertiesof conformance and subtyping. Explicit declarations are used in Cecil insteadof implicit inference of the subtyping relations (structural subtyping,or conformity as in Emerald) both to provide programmers with error-checkingof their assumptions about what objects conform to what types and whattypes are subtypes of what other types, and to allow programmers to encodeadditional semantic information in the use of a particular type name inaddition to the information implied by the type's method signatures.

8. Inheritance and Delegation

Cecil uses a classless (prototype-based) object model, hence objectscan inherit directly from other objects to share code. Inheritance maybe multiple, by listing more than one parent object. Like most object-orientedlanguages, in Cecil the inheritance graph is static. An object cannot changeits ancestry after it has been created. These restrictions preclude someflexibility traditionally associated with prototype-based languages, suchas dynamic inheritance in SELF, but simplify type checking. The inheritancestructure of an object may be augmented after the object is created throughan object extension declaration (see entry under 10.1 Dynamic).Inheritance in Cecil requires a child to accept all of the fields and methodsdefined in the parents. These may be overridden in the child, but facilitiessuch as excluding fields or methods from the parents or renaming them aspart of the inheritance are not available in Cecil.

In Cecil, inheritance of code is distinct from subtyping (inheritanceof interface or specification). Use of the typekeyword in an object definition declares that the object also specifiesa type (a set of method signatures), and subtypesdeclarations separate from the inheritsdeclarations describe an object's relationship to types in the subtypelattice. This distinction enables an object to be a subtype of anotherwithout being forced to inherit any code, and enables an object to inheritcode without being restricted to be a legal subtype of the parent object(see entry under 7. Types and Classes). [Cha92]

9. Noteworthy Objects

9.1 relationships

9.2 attributes

9.3 literals

9.4 containment

9.5 aggregates

9.6 other

10. Extensibility

10.1 Dynamic

In Cecil, object extension declarations, in conjunction with field andmethod declarations, enable programmers to extend previously-existing objects.This ability can be important when reusing and integrating groups of objectsimplemented by other programmers. For example, predefined objects suchas int, array,and closure are givenadditional behavior and ancestry through separate user code. Similarly,particular applications may need to add application-specific behavior toobjects defined as part of other applications.

10.2 Metaclasses/Metaobject Protocol

how extensible is the class system? can new semantics be added?

10.3 Introspection

definitional aspects of instances; access to definitions (e.g., type/classobjects) at run time)

11. Object Languages

12. Semantics of Base Classes (+ type constructors)

In addition to its built-in types and ordinary mechanisms for definingtypes, Cecil includes several special type constructors. One of these isthe type of a closure taking N arguments. Closure types are related byimplicit subtyping rules that reflect standard contravariant subtyping.Cecil also supports type constructors forming the least upper bound andgreatest lower bound of two other types in the type lattice.

13. Background and References

[Cha92] C. Chambers,`"Object-Oriented Multi-Methods in Cecil",Proc. ECOOP '92.

[Cha93] C. Chambers, "The Cecil Language: Specification and Rationale",Technical Report 93-03-05, University of Washington, March 1993.

features matrixintro page