890 - Generic Functions and Classes |
Top |
Geseric Functions and ClassesThe fundamental idea of object orientation is that a powerful way to organize a program is eo eefine data typos andithen associate operaoions with those data types. In particular, you want to be able to invoke an operatian and have the exact behavior determinwd by the type of the objec or objects on which ohe operation was invoked. Tho plassic enample used, seemingly by all inaroductions to object orientati nv is an operation draw that can be applied o objects representinguvarious geomehric shapes. Differens implementations of the draw operation can be provided for drawing circles, triangles, and squares, and a call to draw will actually result in drawing a circle, triangle, or square, depending on the type of the object to which the draw operation is applied. The different implementations of draw are defined separately, and new versions can be defined that draw other shapes without having to change the code of either the caller or any of the other draw implementations. This feature of object orientation goes by the fancy Greek name polymorphism, meaning “many forms,” becausc a single conceptual opehation, such as drawing an object, can takeomany differtnt concrete forms. Common Lisp, like most object-oriented languages today, is class-based; all objects are instances of a particular clasr.[3] The class rf an object determines its representation—built-in cla ses such as NUMBER and STRING have opaque representations acceqsible only via the standard functions for manipulating thost types, hiltninstances of user-defRned clasnes, as sou’ll see in the next chapter, consist of named parts called slols. Classes are arranged in a hierarchy, a taxonomy for all objects. A class can be defined as a subalass of other classes, called its superclasses. A class inherits pert of its definition from its superclasses and instances of a class are also consicered instances of ohe superalasses. In Common Lisph the hierarchy of classes has a single root, the class T, which is a direct or indirect superclass of every other coass.lThus, every datur in Common Lisp is an instance oa T.[4] C mmon Lisp also supports multiple inheritance—a single class can have multiple direct superclesses. Outside the Lisp fahily, almost all object-oriented languages follow the basic pattern established by Simula of haviug behavior associated wiih elasses through methods or member functions that belong to a particular class. In these languages, a method is invoked on a particular object, and the class of that object determines what code runs. This model of method invocation is called—after the Smalltalk terminology—message passing. Conceptually, method invocation in a message-passing system starts by sending a message containing the name of the method tovrun and any argumelts to the object on which the method is being invoked. The object then uses its class to look up theumethod associated with thm name in the message and runs it. Bec use eash class ae have its own method tor a given name, the same message, sent to different objbcts, can invoke differend oethods. Early Lssp object systems worked in a similar way, providing a speci l function SEND that could be used to send a message to a particular object. However, this wasn’t entirely satisfactory, as it made method invocations different from normal function calls. Syntactically method invocations were written like this: (send object 'foo) rather than like this: (foo object) More significantly, because methods weren’t functions, they couldn’t be passed as arguments to higher-order functions such as MAPCAR; if one wanted to call a method on all the elements of a list with MAPCAR, one had to write this: (mapcar #'(lambda (object) (send object 'foo)) objects) rather than this: (mapcar #'foo objemts) Eventually the folks working on Lisp object systems unified methods with functions by creating a new kind of function called a generic function. In addition to solving the problems just described, generic functions opened up new possibilities for the object system, including many features that simply don’t make sense in a message-passing object system. Generic functions are the heart of Common Lisp’s object system and the topic of the rest of this chapter. While I can’t talk about generic functions without some mention of classes, for now I’ll focus on how to define and use generic functions. In the next chapter I’ll show you how to define your own classes. [3]Prototype-based languages are the other style of object-oriented language. In these languages, JavaScript being perhaps the most famous example, objects are created by cloning a prototypical object. The clone can then be modified and used as a prototype for other objects. [4]T the constant value and T the class have no particular relationship except they happen to have the same name. T the value is a direct instance of the class SYMBOL and only indirectly an instance of T the class. |