[Next] [Previous] [Up] [Top] [Contents] [Index]

2.2 Methods

2.2.1 Argument Specializers and Multi-Methods

In Cecil, a method specifies the kinds of arguments for which its code is designed to work. For each formal argument of a method, the programmer may specify that the method is applicable only to actual arguments that are implemented or represented in a particular way, i.e., that are equal to or inherit from a particular object. These specifications are called argument specializers, and arguments with such restrictions are called specialized arguments. The r@rectangle notation specializes the r formal argument on the rectangle object, implying that the method is intended to work correctly with any actual argument object that is equal to or a descendant of the rectangle object as the r formal. An unspecialized formal argument (one lacking a @... suffix), such as s and new_center in the move_to method above, is treated as being specialized on the predefined object any that is implicitly an ancestor of all other objects; consequently an unspecialized formal can accept any argument object.

Methods may be overloaded, i.e., there may be many methods with the same name, as long as the methods with the same name and number of arguments differ in their argument specializers. Methods with different numbers of arguments are independent; the system considers the number of arguments to be part of the method's name. When sending a message of a particular name with a certain number of arguments, the method lookup system (described in section 2.7) will resolve the overloaded methods to a single most-specific applicable method based on the dynamic values of the actual argument objects and the corresponding formal argument specializers of the methods.

Zero, one, or several of a method's arguments may be specialized, thus enabling Cecil methods to emulate normal undispatched functions (by leaving all formals unspecialized, as in move_to above) and singly-dispatched methods (by specializing only the first argument, as in the area methods) as well as true multi-methods (as in the specialized version of draw for rectangles on X windows). Statically-overloaded functions and functions declared via certain kinds of pattern-matching also are subsumed by multi-methods. Callers which send a particular message to a group of arguments are not aware of the collection of methods that might handle the message or which arguments of the methods are specialized, if any; these are internal implementation decisions that should not affect callers. In particular, a given message can initially be implemented with a single unspecialized procedure and then later extended or replaced with several specialized implementations, without affecting clients of the original method, as occurs with the draw methods in the previous example. In contrast, CLOS has a "congruent lambda list" rule that requires all methods in a particular generic function to specialize on the same argument positions.

Argument specializers are distinct from type declarations. Argument specializers restrict the allowed implementations of actual arguments and are used as part of method lookup to locate a suitable method to handle a message send. Type declarations require that certain operations be supported by argument objects, but place no constraints on how those operations are implemented. Type declarations have no effect on method lookup.

The name of a formal may be omitted if it is not needed in the method's body. Unlike singly-dispatched languages, there is no implicit self formal in Cecil; all formals are listed explicitly.

Cecil's classless object model combines with its definition of argument specializers to support something similar to CLOS's eql specializers. In CLOS, an argument to a multi-method in a generic function may be restricted to apply only to a particular object by annotating the argument specializer with the eql keyword. Cecil needs no extra language mechanism to achieve a similar effect, since methods already are specialized on particular objects. Cecil's mechanism differs from CLOS's in that in Cecil such a method also will apply to any children of the specializing object, while in CLOS the method will apply only for that object. Dylan, a descendant of CLOS, has a singleton specializer that is analogous to CLOS's eql specializer [Apple 92].

As mentioned in subsection 2.1.3, methods can be added to existing objects without needing to modify those existing objects. This facility, lacking in most object-oriented languages, can make reusing existing components easier since they can be adapted to new uses by adding methods, fields, and even parents to them.

The names of methods and fields are in a name space separate from the name space of objects and variables. A method or field can have the same name as a variable or object without confusion.