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

2.3 Fields

2.3.3 Copy-Down vs. Shared Fields

By default, each object inheriting a field declaration receives its own space to hold its version of the field's contents, and the field's accessor methods access the memory space associated with their first argument. Such a "copy-down" field acts much like an instance variable declaration in a class-based language, since each object gets its own local copy of the field. Alternatively, a field declaration may be prefixed with the shared keyword, implying that all inheriting objects should share a single memory location. A shared field thus acts like a class variable.

Supporting both copy-down and shared fields addresses weaknesses in some other prototype-based object-oriented languages relative to class-based languages. In class-based languages, instance variables declared in a superclass are automatically copied down into subclasses; the declaration is inherited, not the variable's contents. Class variables, on the other hand, are shared among the class, its instances, and its subclasses. In some prototype-based languages, including Self and Actra [Lieberman 86], instance variables of one object are not copied down into inheriting objects; rather, these variables are shared, much like class variables in a class-based language. In Self, to get the effect of object-specific state, most data types are actually defined with two objects: one object, the prototype, includes all the instance-specific variables that objects of the data type need, while the other object, the traits object, is inherited by the prototype and holds the methods and shared state of the data type [Ungar et al. 91]. New Self objects are created by cloning (shallow-copying) a prototype, thus giving new objects their own instance variables while sharing the parent traits object and its methods and state. Defining a data type in two pieces can be awkward, especially since it separates the declarations of instance variables from the definitions of the methods that access them. Furthermore, inheriting the instance variable part of the implementation of one data type into another is more difficult in Self than in class-based languages, relying on complex inheritance rules and dynamic inheritance [Chambers et al. 91] or programming environment support [Ungar 95]. Copy-down fields in Cecil solve these problems in Self without sacrificing the simple classless object model. In Cecil, only one object needs to be defined for a given data type, and the field declarations can be in the same place as the method declarations that access them. This design increases both conciseness and readability, at the cost of some additional language mechanism.

Cecil objects are created only through object declarations and object constructor expressions; these two expressions have similar run-time effects, with the former additionally binding statically-known names to the created objects enabling methods and fields to be associated with them and enabling other objects to inherit from them. Cecil needs no other primitive mechanism to create or copy objects as do other languages. Self provides a shallow-copy (clone) primitive in addition to object literal syntax (analogous to Cecil's object constructor expressions), in part because there are no "copy-down" data slots in Self. Class-based languages typically include several mechanisms for creating instances and classes and relations among them. On the other hand, creating an object by inheriting from an existing object may not be as natural as creating an object by copying an existing object.