Next: I/O system, Previous: Bitwise manipulation, Up: System facilities
Scheme48 supports a CLOS-style generic procedure dispatch system, based
on type predicates. The main interface is exported by methods
.
The internals of the system are exposed by the meta-methods
structure, but they are not documented here. The generic dispatch
system is used in Scheme48's writer and numeric
system.
Types in Scheme48's generic dispatch system are represented using type predicates, rather than having every object have a single, well-defined `class.' The naming convention for simple types is to prefix the type name with a colon. The types support multiple inheritance. Method specificity is determined based on descending order of argument importance. That is, given two methods, M & N, such that they are both applicable to a given sequence of arguments, and an index i into that sequence, such that i is the first index in M's & N's lists of argument type specifiers, from left to right, where the type differs: if the type for M's argument at i is more specific than the corresponding type in N's specifiers, M is considered to be more specific than N, even if the remaining argument type specifiers in N are more specific.
Defines name to be a simple type with the given predicate and the given supertypes.
Defines proc-name to be a generic procedure that, when invoked, will dispatch on its arguments via the method table that method-table-name is defined to be and apply the most specific method it can determine defined in the method-table-name method table to its arguments. The convention for naming variables that will be bound to method tables is to add an ampersand to the front of the name. Prototype is a suggestion for what method prototypes should follow the shape of, but it is currently ignored.
Adds a method to method-table, which is usually one defined by
define-generic
.1 Prototype should be a list whose elements may be either identifiers, in which case that parameter is not used for dispatching, or lists of two elements, thecar
of which is the parameter name and thecadr
of which should evaluate to the type on which to dispatch. As in many generic dispatch systems of similar designs, methods may invoke the next-most-specific method. By default, the namenext-method
is bound in body to a nullary procedure that calls the next-most-specific method. The name of this procedure may be specified by the user by putting the sequence"next"
next-method-name in prototype, in which case it will be next-method-name that is bound to that procedure. For example:(define-method &frob ((foo :bar) "next" frobozz) (if (mumble? foo) (frobozz) ; Invoke the next method. (yargh blargle foo)))
A number of simple types are already defined & exported by the
methods
structure. Entries are listed as type-name
<- (
supertype ...),
predicate
:values <- (), (lambda (x) #t)
— Abstract supertype of
all run-time values
:value <- (:values), (lambda (x) #t)
— Abstract
supertype of all first-class values
:zero <- (:values), (lambda (x) #f)
— Type that no
objects satisfy
:number <- (:value), number?
:complex <- (:number), complex?
— (This happens to be
equivalent to :number
.)
:real <- (:complex), real?
:rational <- (:real), rational?
:integer <- (:rational), integer?
:exact-integer <- (:integer),
(lambda (x) (and (integer? x) (exact? x)))
:boolean <- (:value), boolean?
:symbol <- (:value), symbol?
:char <- (:value), char?
:null <- (:value), null?
:pair <- (:value), pair?
:vector <- (:value), vector?
:string <- (:value), string?
:procedure <- (:value), procedure?
:input-port <- (:value), input-port?
:output-port <- (:value), output-port?
:eof-object <- (:value), eof-object?
:record <- (:value), record?
[1] There is an internal interface, a sort of meta-object protocol, to the method dispatch system, but it is not yet documented.