[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A class is an object that determines the structure and behavior of
a set of other objects, which are called its instances. However,
in this document, the word instance usually means an instance of
the class <instance>
.
A class can inherit structure and behavior from other classes. A class whose definition refers to other classes for the purpose of inheriting from them is said to be a subclass of each of those classes. The classes that are designated for purposes of inheritance are said to be superclasses of the inheriting class.
A class can have a name. The procedure class-name
takes a
class object and returns its name. The name of an anonymous class is
#f
.
A class C_1 is a direct superclass of a class C_2 if C_2 explicitly designates C_1 as a superclass in its definition. In this case, C_2 is a direct subclass of C_1. A class C_n is a superclass of a class C_1 if there exists a series of classes C_2, ..., C_n-1 such that C_i+1 is a direct superclass of C_i for all i between 1 and n. In this case, C_1 is a subclass of C_n. A class is considered neither a superclass nor a subclass of itself. That is, if C_1 is a superclass of C_2, then C_1 is different from C_2. The set of classes consisting of some given class C along with all of its superclasses is called "C and its superclasses."
Each class has a class precedence list, which is a total ordering on the set of the given class and its superclasses. The total ordering is expressed as a list ordered from the most specific to the least specific. The class precedence list is used in several ways. In general, more specific classes can shadow, or override, features that would otherwise be inherited from less specific classes. The method selection and combination process uses the class precedence list to order methods from most specific to least specific.
When a class is defined, the order in which its direct superclasses are mentioned in the defining form is important. Each class has a local precedence order, which is a list consisting of the class followed by its direct superclasses in the order mentioned in the defining form.
A class precedence list is always consistent with the local precedence order of each class in the list. The classes in each local precedence order appear within the class precedence list in the same order. If the local precedence orders are inconsistent with each other, no class precedence list can be constructed, and an error is signalled.
Classes are organized into a directed acyclic graph. There are
two distinguished classes, named <object>
and <instance>
.
The class named <object>
has no superclasses. It is a superclass
of every class except itself. The class named <instance>
is a
direct subclass of <object>
and is the base class for
instance objects. Instances are special because SOS has
efficient mechanisms for dispatching on them and for accessing their
slots.
1.1 Class Datatype 1.2 Predefined Classes 1.3 Record Classes 1.4 Specializers
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The procedures in this section may be used to construct and inspect classes.
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
initial-value
nor the initializer
property is specified,
the slot has no default initial value.
initializer
initializer
procedure is the
initial value of the slot.
accessor
make-class
will add
an accessor method for this slot to the procedure. See section 3. Slots.
modifier
make-class
will add
a modifier method for this slot to the procedure. See section 3. Slots.
initpred
make-class
will add
an "initialized?" predicate method for this slot to the procedure.
See section 3. Slots.
Slot properties are combined in slightly complicated ways.
initial-value
and
initializer
for a slot in a given call to make-class
; at
most one of these properties may be given.
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 <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 ())))) |
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])
#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])
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)
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-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 '())) |
(make-class (class-name superclass1) (list superclass1 superclass2 ...) '()) |
#t
if object is a class, otherwise returns
#f
.
#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.
instance-class
is faster than object-class
.
make-class
when class was created.
make-class
when class was created, this list is
equal?
to that argument. The returned value must not be
modified.
make-class
that created class; it does not
contain slots that were inherited. The returned value must not be
modified.
<object>
as its
last element. The returned value must not be modified.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
SOS provides a rich set of predefined classes that can be used to specialize methods to any of Scheme's built-in datatypes.
<object>
. The members of this class are the objects that satisfy
the predicate instance?
.
<object>
. The members of each class are the
objects that satisfy the corresponding predicate; for example, the
members of <procedure>
are the objects that satisfy
procedure?
.
<procedure>
.
<instance>
.
<method>
.
The following are the classes of Scheme numbers. Note that
object-class
will never return one of these classes; instead it
returns an implementation-specific class that is associated with a
particular numeric representation. The implementation-specific class is
a subclass of one or more of these implementation-independent classes,
so you should use these classes for specialization.
<number>
is a
direct subclass of <math-object>
, <complex>
is a direct
subclass of <number>
, <real>
is a direct subclass of
<complex>
, etc.
<exact>
is a direct
subclass of <number>
, <exact-complex>
is a direct
subclass of <exact>
and <complex>
, and in general, each is
a direct subclass of preceding class and of the class without the
exact-
prefix.
<inexact>
is a direct
subclass of <number>
, <inexact-complex>
is a direct
subclass of <inexact>
and <complex>
, and in general, each
is a direct subclass of preceding class and of the class without the
inexact-
prefix.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
SOS allows generic procedures to discriminate on record types.
This means that a record structure defined by means of
make-record-type
or define-structure
can be passed as an
argument to a generic procedure, and the generic procedure can use the
record's type to determine which method to be invoked.(2)
In order to support this, SOS accepts record type descriptors in all contexts that accept classes. Additionally, every record type descriptor has an associated SOS class; either the class or the record type can be used with equivalent results.
record-type?
). Returns the class
associated with record-type.
record?
). Returns the class associated with
record. This is equivalent to
(record-type-class (record-type-descriptor record)) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A specializer is a generalization of a class. A specializer is any one of the following:
A specializer may be used in many contexts where a class is required,
specifically, as a method specializer (hence the name), as the second
argument to subclass?
, and elsewhere.
#t
if object is a specializer, otherwise returns
#f
.
#t
if specializer1 and specializer2 are
equivalent, otherwise returns #f
. Two specializers are
equivalent if the lists returned by specializer-classes
contain
the same elements.
#t
if object is a union specializer, otherwise
returns #f
.
#t
if object is a list of specializers, otherwise
returns #f
.
#t
if specializers1 and
specializers2 are equivalent, otherwise returns #f
.
Two specializers lists are equivalent if each of their corresponding
elements is equivalent.
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |