Class Datatype - SOS 1.9
Description: SOS 1.9

Next: Predefined Classes, Previous: Classes, Up: Classes

### 1.1 Class Datatype

The procedures in this section may be used to construct and inspect classes.

— Procedure: make-class name direct-superclasses direct-slots

> Creates and returns a new class object.

> Name is used for debugging: it is a symbol that appears in the printed representation of the class and has no role in the semantics of the class. Alternatively, name may be `#f` to indicate that the class is anonymous.

> Direct-superclasses must be a list of class objects. The new class inherits both methods and slots from the classes in this list. Specifying the empty list for direct-superclasses is equivalent to specifying `(list <instance>)`.

> Direct-slots describes additional slots that instances of this class will have. It is a list, each element of which must have one of the following forms:

>               name
>               (name . plist)

> where name is a symbol, and plist is a property list. The first of these two forms is equivalent to the second with an empty plist.

> Each of the elements of direct-slots defines one slot named name. Plist is used to describe additional properties of that slot. The following properties are recognized:

> `initial-value`
>   This property specifies the default initial value for the slot, i.e. the value stored in the slot when an instance is created and no value is explicitly specified by the instance constructor. If neither the `initial-value` nor the `initializer` property is specified, the slot has no default initial value.
> `initializer`
>   This property specifies a procedure of no arguments that is called by an instance constructor whenever an instance containing this slot is created. The value returned by the `initializer` procedure is the initial value of the slot.
> `accessor`
>   This property specifies a generic procedure; `make-class` will add an accessor method for this slot to the procedure. See Slots.
> `modifier`
>   This property specifies a generic procedure; `make-class` will add a modifier method for this slot to the procedure. See Slots.
> `initpred`
>   This property specifies a generic procedure; `make-class` will add an “initialized?” predicate method for this slot to the procedure. See Slots.

> Slot properties are combined in slightly complicated ways.

> - It is not allowed to specify both `initial-value` and `initializer` for a slot in a given call to `make-class`; at most one of these properties may be given.
> - If a slot is specified for a given class, and a slot of the same name is inherited from a superclass, then the slot properties for the two slots are combined. Slot properties from the subclass shadow those of the superclass. However, if a superclass has a slot property, and the subclass does not, the property is inherited. The resulting class never has more than one slot of a given name.
> - When combining superclass and subclass slots, `initial-value` and `initializer` shadow one another. In other words, regardless of the inherited slot properties, the resulting slot has at most one of these two properties.

> Examples of `make-class`:

>               (define <cell>
>                 (make-class '<cell> '() '()))

>               (define-generic cell-name (cell))
>               (define-generic cell-width (cell))
>               (define-generic cell-height (cell))
>               (define-generic cell-components (cell))
>               (define-generic set-cell-components! (cell components))

>               (define <contact>
>                 (make-class '<contact>
>                             (list <cell>)
>                             `((name accessor ,cell-name))))

>               (define <compound-cell>
>                 (make-class '<compound-cell>
>                             (list <cell>)
>                             `((width accessor ,cell-width)
>                               (height accessor ,cell-height)
>                               (components accessor ,cell-components
>                                           modifier ,set-cell-components!
>                                           initial-value ()))))

— Syntax: define-class name direct-superclasses direct-slot ...

> Define name to be a class. In its basic form, `define-class` might have been defined by

>               (define-syntax define-class
>                 (syntax-rules ()
>                   ((define-class name (class ...) slot ...)
>                    (define name
>                      (make-class (quote name)
>                                  (list class ...)
>                                  (quote (slot ...)))))))

> Note that slot properties are handled specially by `define-class`. If a direct-slot specifies a slot properties property list, the keys of the property list (i.e. the even-numbered elements) are not evaluated, while the datums of the property list are evaluated. The expansion above does not show the proper treatment of slot properties.

> In addition to the slot properties recognized by `make-class`, `define-class` recognizes a special slot property, called `define`. The `define` property specifies that some or all of the slot accessors should be defined here; that is, generic procedures should be constructed and bound to variables, and then the accessor methods added to them.

> The argument to the `define` property is a list containing any combination of the symbols `accessor`, `modifier`, and `initpred`. As an abbreviation, the argument may be one of these symbols by itself, which is equivalent to the list containing that symbol. Also, the argument may be the symbol `standard`, which is equivalent to `(accessor modifier)`.

> The argument to `define` specifies the accessors that will be defined by this form. The accessors are defined using default names, unless the names are overridden by the corresponding slot property. The default names for a class `<foo>` and a slot `bar` are `foo-bar`, `set-foo-bar!`, and `foo-bar-initialized?`, respectively for the accessor, modifier, and initpred. For example,

>               (define-class foo ()
>                 (bar define accessor))

> defines an accessor called `foo-bar`, but

>               (define-class foo ()
>                 (bar define accessor accessor foo/bar))

> instead defines an accessor called `foo/bar`. Finally,

>               (define-class foo ()
>                 (bar accessor foo/bar))

> doesn't define any accessor, but assumes that `foo/bar` is a previously-defined generic procedure and adds an accessor method to it.

> `define-class` permits the specification of class options, which are options that pertain to the class as a whole. Class options are specified by overloading name: instead of a symbol, specify a pair whose car is a symbol and whose cdr is an alist. The following class options are recognized:

> `(predicate [`name`])`
>   Specifies that a predicate procedure should be defined for this class. Name must be either a symbol or `#f`: a symbol specifies the name that will be bound to the predicate procedure, and `#f` specifies that no predicate procedure should be defined. If name is omitted, or if no `predicate` option is specified, a predicate procedure is defined by appending `?` to the name of the class. If the class name is surrounded by angle brackets, they are stripped off first. For example, the default predicate name for the class `<foo>` is `foo?`.
> `(constructor [`name`]` slot-names`[`n-init-args`])`
>   Specifies that a constructor procedure should be defined for this class. Name must be a symbol, which is the name that will be bound to the constructor procedure; if omitted, a default name is formed by prepending `make-` to the name of the class. If the class name is surrounded by angle brackets, they are stripped off first. For example, the default constructor name for the class `<foo>` is `make-foo`.

>   Slot-names and n-init-args correspond to the arguments of the respective names accepted by `instance-constructor`, and can take any of the allowed forms for those arguments.

> `(separator` string`)`
>   Specifies how names for slot accessors are constructed. If this option isn't given, the name of a slot accessor is formed by concatenating the name of the class with the name of the slot, with a hyphen between them. When this option is given, string is used instead of the hyphen. For example, normally a slot accessor for the slot `bar` in the class `foo` is called `foo-bar`. A class option `(separator ".")` will cause the slot accessor to be called `foo.bar`, the modifier to be called `set-foo.bar!`, and the initialization predicate to be called `foo.bar?`.

> Examples of `define-class` (compare these to the similar examples for `make-class`):

>               (define-class <cell> ())

>               (define-generic cell-name (cell))
>               (define-generic cell-width (cell))
>               (define-generic cell-height (cell))
>               (define-generic cell-components (cell))
>               (define-generic set-cell-components! (cell components))

>               (define-class (<contact> (constructor (name) no-init)) (<cell>)
>                 (name accessor cell-name))

>               (define-class (<compound-cell> (constructor ())) (<cell>)
>                 (width accessor cell-width)
>                 (height accessor cell-height)
>                 (components accessor cell-components
>                             modifier set-cell-components!
>                             initial-value '()))

— Procedure: make-trivial-subclass superclass1 superclass2 ...

> This convenience procedure makes a subclass that defines no new slots, and that inherits from the given superclasses. It is equivalent to the following

>               (make-class (class-name superclass1)
>                           (list superclass1 superclass2 ...)
>                           '())

— Procedure: class? object

> Returns `#t` if object is a class, otherwise returns `#f`.

— Procedure: subclass? class specializer

> Returns `#t` if class is a subclass of specializer, otherwise returns `#f`. If specializer is a class, the result follows from the above definition of subclass, except that a class is a subclass of itself. If specializer is a record type, it is equivalent to having used the `record-type-class` of the record type. Finally, if specializer is a union specializer, `subclass?` is true if class is a subclass of one or more of the component classes of specializer.

— Procedure: object-class object

> Returns the class of object. Object may be any Scheme object; if object is known to be an instance, `instance-class` is faster than `object-class`.

— Procedure: class-name class

> Returns the name of class. This is the name argument passed to `make-class` when class was created.

— Procedure: class-direct-superclasses class

> Returns a list of the direct superclasses of class. If a non-empty direct-superclasses argument was passed to `make-class` when class was created, this list is `equal?` to that argument. The returned value must not be modified.

— Procedure: class-direct-slot-names class

> Returns a list of symbols that are the names of the direct slots of class. This list contains only those slots that were defined in the call to `make-class` that created class; it does not contain slots that were inherited. The returned value must not be modified.

— Procedure: class-precedence-list class

> Returns a list of the superclasses of class. The order of this list is significant: it is the method resolution order. This list will always have class as its first element, and `<object>` as its last element. The returned value must not be modified.