/usr/lib/s9fes/sos.txt is in scheme9 2010.11.13-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 | SOS - A simple Scheme Object System
-----------------------------------
By Nils M Holm, 2010
SOS is an extension for object oriented programming in Scheme.
It was inspired by CLOS, the Common Lisp Object System, but it
is much simpler. However, it still provides:
- multiple inheritance
- multi-method dispatch
- generic procedures
- a meta-object protocol
Defining Classes
----------------
A "class" is a description of the internal structure of new
data objects called the "instances" of that class. It may be
thought of as a template for creating data objects sharing
the same structure. An instance is sometimes also called an
"object", but this name is avoided here, because generic
Scheme data objects are also referred to as "objects."
An instance is basically a vector whose elements are named. A
named element is called a "slot". Programs can retrieve values
stored in slots and replace the objects stored in them. See the
section on "instances" for details.
Slots are either defined in a DEFINE-CLASS form or "inherited"
from a superclass. See below for details.
(DEFINE-CLASS <NAME> (<CLASS> ...) <SLOT> ...) [SYNTAX]
==> UNSPECIFIC
DEFINE-CLASS creates a new class with the given <name> and the
given <slot>s. After evaluating DEFINE-CLASS, the new class can
be referred to by using <name>.
A <slot> may have three different forms:
symbol
(symbol)
(symbol <expression>)
In either of the three cases the symbol names the slot. When an
<expression> is also given, it will be evaluated by DEFINE-CLASS
and stored as a default value for that slot. When no default
value is present, () will be used.
The new class will be a "subclass" of each <class> listed in the
second argument and hence each of those classes will become a
"superclass" of the new class.
A class is called s subclass of another class, if it inherits
any slots or methods (q.v.) from that class. For example:
(define-class point () x y)
(define-class color () red green blue)
(define-class colored-point (point color))
Here the classes POINT and COLOR are "base classes" with no
superclasses. POINT defines the instance variables X and Y, and
COLOR defines the instance variables RED, GREEN, and BLUE. The
COLORED-POINT class is derived from both POINT and COLOR. It
does not define any "own" slots ("direct slots"). However, since
it is a subclass of both POINT and COLOR, it "inherits" all of
their variables, so an instance of COLORED-POINT would have
slots named X, Y, RED, GREEN, and BLUE.
Methods are inherited in the same way:
(define-generic move)
(define-method (move (p point) x y)
(slot-set! p 'x x)
(slot-set! p 'y y))
(move (make-instance colored-point) 17 25)
Although the MOVE method is specialized in the POINT class, it
also works for the COLORED-POINT class, because COLORED-POINT
is derived from POINT.
Systems that allow a class to be derived from multiple
superclasses is said to support "multiple inheritance."
SOS support multiple inheritance to some degree. When a naming
conflict occurs because multiple superclasses of a given class
define slots of the same name, SOS will signal an error.
(CLASS? OBJECT) ==> BOOLEAN [PROCEDURE]
The CLASS? predicate returns truth if the given OBJECT is a
class.
Meta Object Protocol
--------------------
A Meta Object Protocol (MOP) simply exposes the fact that a
class is an instance (of the class "class"). Of course, this
simple realization has some implications. When you can store
values in slots of a class, you can change the way in which
the entire object system works.
The purpose of a MOP is far beyond the scope of this document.
The following procedures are part of the SOS MOP.
(CLASS-CPL CLASS) ==> LIST [MOP PROCEDURE]
Return the Class Precedence List (CPL) of the given class. The
CPL of a class specifies the types of generic procedures (q.v.)
by which an instance of the given class wants to be handled.
However, it does not just name one type, but a list of types
in order of descending precedence. When no method specializing
in the first (most preferred) type in the list can be found,
the second one will be tried, and so on. Given the above
definitions of the POINT and COLORED-POINT classes:
(map class-name (class-cpl colored-point))
==> (colored-point point color)
The CPL is generated by the COMPUTE-CLASS-CPL procedure. (Q.v.)
(CLASS-DIRECT-SLOTS CLASS) ==> LIST [MOP PROCEDURE]
Return the "direct slots" of the given class. A direct slot is a
slot that has been created when defining the class, i.e. a slot
that has *not* been inherited by a superclass:
(class-direct-slots point) ==> ((x ()) (y ()))
(class-direct-slots colored-point) ==> ()
(CLASS-DIRECT-SUPERS CLASS) ==> LIST [MOP PROCEDURE]
Return the "direct superclasses" of the given class. A direct
superclass is a superclass from which the given class was
*directly* derived, i.e. the superclass was listed in the
definition and not inherited from a direct superclass. In the
following example, the class FOO is indirectly inherited by
class BAZ, but FOO is not a direct superclass of BAZ:
(define-class foo ())
(define-class bar (foo))
(define-class baz (bar))
Hence:
(map class-name (class-cpl baz)) ==> (baz bar foo)
(map class-name (class-direct-supers baz)) ==> (bar)
(CLASS-NAME CLASS) ==> SYMBOL [MOP PROCEDURE]
Return the name of the given class. A class itself is an
abstract entity that is typically bound to a name. The
DEFINE-CLASS form does both of this: create a class of the
given name and bind it to the same name:
(define-class foo ())
After evaluating the DEFINE-CLASS form, the symbol FOO is bound
to a class:
foo ==> #<procedure>
(The class is encapsulated in a procedure to keep its cyclic
structure hidden from the Scheme printer.)
Of course, SOS classes are first-class objects, so they can be
bound to different symbols:
(define bar foo)
bar ==> #<procedure>
The CLASS-NAME procedure always returns the name of the class
itself, though (i.e. the name given to it when it was created):
(class-name bar) ==> foo
(COMPUTE-CLASS-CPL LIST) ==> LIST [MOP PROCEDURE]
Given a list of classes, compute the CPL (see CLASS-CPL) of the
class listed first in LIST. LIST contains the class whose CPL is
to be computed as well as the direct superclasses of that class:
(list <root-class> <superclass> ...)
COMPUTE-CLASS-CPL returns a new list containing the CPL of
<root-class>. The CPL contains all superclasses of the given
class as well as the superclasses of the superclasses, and so
on. What is particularly important is the order of the CPL,
because more specific classes must always precede less specific
classes in the list (so that generic procedures (q.v.) will
apply the most specific method to each set of arguments.)
The CPL is generated by sorting the list of (direct or indirect)
subclasses topologically in such a way that classes that are
closer to the <root-class> will come first in the resulting
list. Given the following class hierarchy
(define-class pixel () x y)
(define-class voxel (pixel) z)
(define-class color () r g b)
(define-class c-voxel (voxel color))
the CPL of the C-VOXEL class would look like this:
(map class-name
(compute-class-cpl (list c-voxel voxel color)))
==> (c-voxel voxel color pixel)
When a class inherits from multiple superclasses (like C-VOXEL
above), the order of precedence of superclasses at the same
"level" of the class hierachy is determined by the order in
which the superclasses were specified when defining the derived
class. In the following example, the order of COLOR and VOXEL is
reversed:
(map class-name
(compute-class-cpl (list c-voxel color voxel)))
==> (c-voxel color voxel pixel)
(COMPUTE-CLASS-SLOTS LIST) ==> LIST [MOP PROCEDURE]
Return the slots of all classes listed in LIST, including the
slots inherited by those classes. This procedure is used to
generate the slots of a new class. Given the definition of the
C-VOXEL class in the previous entry,
(compute-class-slots (list voxel color))
==> ((z ()) (r ()) (g ()) (b ()) (x ()) (y ()))
Note that the order of slots does not matter, because slots are
(even internally!) referred to by their names.
Instances
---------
A class is merely a "template" that can be used to generate any
number of "instances". An instance of a class is sometimes also
called an "object" (although not in this document).
(MAKE-INSTANCE CLASS <INIT-ARG> ...) ==> INSTANCE [PROCEDURE]
Create a fresh instance of the given class and return it. Each
slot of the instance will be initialized with the default value
that was assigned to the slot when the class was defined:
(define-class point () (x 1) (y 2))
(let ((p (make-instance point)))
(list (slot-ref p 'x)
(slot-ref p 'y))) ==> (1 2)
Slot values can be assigned dynamically when an instance is
created by passing some <INIT-ARG>s to the procedure. Each
<INIT-ARG> consists of a slot name and a value to be stored in
that slot:
(let ((p (make-instance point 'x 17 'y 25)))
(list (slot-ref p 'x)
(slot-ref p 'y))) ==> (17 25)
Additional initialization can be performed by a method of the
generic procedure INITIALIZE (q.v.) which is applied to the
instance after evaluating the <INIT-ARG>s:
(define-class s-point () (x 1) (y 2) (scale 100))
(define-method (initialize (p s-point))
(slot-set! p 'x (* (slot-ref p 'scale)
(slot-ref p 'x)))
(slot-set! p 'y (* (slot-ref p 'scale)
(slot-ref p 'y))))
(let ((p (make-instance s-point 'x 17 'y 25)))
(list (slot-ref p 'x)
(slot-ref p 'y))) ==> (1700 2500)
(CLASS-OF OBJECT) ==> CLASS [PROCEDURE]
(INSTANCE-CLASS INSTANCE) ==> CLASS [PROCEDURE]
Return the class of the given instance:
(class-name (class-of (make-instance point)))
==> point
The difference between CLASS-OF and INSTANCE-CLASS is that
CLASS-OF is more general and will return "built-in" classes
(q.v.) for primitive Scheme objects, while INSTANCE-CLASS can
only be applied to SOS instances.
(INITIALIZE INSTANCE) ==> OBJECT [GENERIC]
INITIALIZE is a generic procedure providing a method for every
class that has been defined using DEFINE-CLASS. Whenever a new
instance is created by MAKE-INSTANCE, INITIALIZE is automatically
applied to that instance. The methods of INITIALIZE are intended
for more elaborate instance initialization. This is done by
redefining a method of INITIALIZE. Consider the following
example:
(define-class timestamp () (time (sys:time)))
In this example, the TIME slot would always be initialized with
the value that SYS:TIME delivered when the TIMESTAMP *class* was
created. To initialize the TIME slot with the current time when
an instance of TIMESTAMP is created, a method specializing in
the TIMESTAMP class would be added to INITIALIZE:
(define-method (initialize (t timestamp))
(slot-set! t 'time (sys:time)))
(INSTANCE? OBJECT) ==> BOOLEAN [PROCEDURE]
The INSTANCE? predicate returns truth if the given OBJECT is an
instance of any class. Note that primitive Scheme objects are
*not* instances of built-in classes, so (instance? "xyz"), for
example, will deliver #F.
(SLOT-REF INSTANCE SYMBOL) ==> OBJECT [PROCEDURE]
Return the value stored in the slot named SYMBOL of the given
INSTANCE.
(SLOT-SET! INSTANCE SYMBOL OBJECT) ==> UNSPECIFIC [PROCEDURE]
Replace the value stored in the slot named SYMBOL of the given
INSTANCE with the given OBJECT.
Generic Procedures
------------------
A "generic procedure" is a set of procedures that specialize in
handling different data types. A procedure that is contained in
a generic procedure is also called a "method".
Generic procedures select methods by "multi-method dispatch".
This means that *all* arguments of a generic procedure are taken
into consideration when looking for the most specific methods
for handling a given application.
Generic procedures are a rather heavy-weight tool. Using it for
trivial tasks is highly inefficient.
(DEFINE-GENERIC <NAME>) ==> UNSPECIFIC [SYNTAX]
Define a new generic procedure and bind it to the given <name>.
When a generic procedure with the given name already exists, all
methods of that generic will be removed!
(DEFINE-METHOD (<NAME> <ARGUMENT> ...) <BODY>) [SYNTAX]
==> UNSPECIFIC
(DEFINE-METHOD (<NAME> <ARGUMENT> ... . SYMBOL) <BODY>)
==> UNSPECIFIC
Add a method to the generic procedure that is bound to <name>.
A method is like an ordinary procedure, but it is never applied
directly but always dispatched by the corresponding generic
procedure. (See APPLY-GENERIC for details on generic procedure
application).
Typically the arguments of a generic procedure are of the form
(symbol class)
where the symbol names the argument and the class is used to
specialize the method. When only a symbol is given, the class
defaults to <TYPE>, which matches any type (i.e. the method
does not specialize at all). A built-in class may be specified
to specialize a method in a native Scheme data type:
(define-generic conc)
(define-method (conc (a <pair>) b)
(append a b))
(define-method (conc (a <string>) (b <string>))
(string-append a b))
(define-method (conc (a <char>) (b <string>))
(string-append (string a) b))
(conc '(1 2 3) 4) ==> (1 2 3 . 4)
(conc "abc" "def") ==> "abcdef"
(conc #\h "ello") ==> "hello"
Like a procedure a method may have a "rest" argument that is
placed after the dot of an improper argument list. This argument
binds to a list of remaining arguments after binding the fixed
variables of the method. The rest argument does not play any
role when dispatching a method.
(APPLY-GENERIC GENERIC LIST) ==> OBJECT [PROCEDURE]
Apply a generic procedure to a list of arguments. The length of
LIST much match the number of arguments of GENERIC.
A generic procedure is applied to its arguments by first
selecting all methods that are "applicable" to the given
arguments. This is done by the COMPUTE-APPLICABLE-METHODS
procedure (q.v.).
Once the set of applicable methods has been obtained, the
most specific one of the methods that still matches the given
arguments will be select. This method is called the "effective
method". It is computed by the COMPUTE-EFFECTIVE-METHOD (q.v.)
procedure.
Finally the effective method is applied to the given arguments
and the result is returned. This final step is the same as in
the APPLY procedure of Scheme.
In case the set of applicable methods is empty, APPLY-GENERIC
calls the NO-APPLICABLE-METHOD procedure.
(CALL-NEXT-METHOD) ==> OBJECT [PROCEDURE]
The CALL-NEXT-METHOD procedure is bound internally in every
method. It pass the arguments received by that message on to
the next-unspecific method. See COMPUTE-EFFECTIVE-METHOD for
details. Here is an example:
(define-class foo ())
(define-class bar (foo))
(define-generic frob)
(define-method (frob (x foo))
'(foo))
(define-method (frob (x bar))
(cons 'bar (call-next-method)))
(frob (make-instance foo)) ==> (foo)
(frob (make-instance bar)) ==> (bar foo)
When CALL-NEXT-METHOD is called and there is no less specific
method, NO-NEXT-METHOD (q.v.) is called instead.
(COMPUTE-APPLICABLE-METHODS LIST1 LIST2) [MOP PROCEDURE]
==> LIST
LIST1 is a list of methods and LIST2 is an (already evaluated)
argument list to be passed to one (or multiple) of of these
methods.
A method is "applicable" to a set of arguments, if the class
of each member of its "specializer" matches the class of the
corresponding argument.
A specializer is the signature of a method. It is a list of
classes that was specified (express or implied) in the
DEFINE-METHOD form that defined the method. For example, the
specializer of the method
(define-method (foo (a <bar>) (b <baz>)) (frob a b))
would be (<bar> <baz>).
An argument matches a class <bar>, if it is of the same class
or of a more specific class than <bar>. A class <x> is more
specific than a class <y>, if <x> was derived (directly or
indirectly) from <x>. For example:
(define-class point () x y)
(define-class c-point (point) color)
(define-generic move)
(define-method (move (p point) (x <number>) (y <number>))
(slot-set! p 'x x)
(slot-set! p 'y y))
(define-generic set-color)
(define-method (set-color (cp c-point) color)
(slot-set! p 'color color))
In this case, the class C-POINT is more specific than POINT (a
C-POINT is a POINT with a color), so the method specializing in
POINT can also be used to move a C-POINT. The SET-COLOR method,
however, specializes in C-POINT and POINT is *less* specific
than C-POINT, so SET-COLOR cannot be used to change the color of
a POINT. Hence:
(compute-applicable-methods
(generic-methods move)
(list (make-instance c-point) 1 2)) ==> (#<method>)
But:
(compute-applicable-methods
(generic-methods set-color)
(list (make-instance point) 'yellow)) ==> ()
Sometimes multiple methods of the same generic procedure may
be applicable to a given set of arguments. In this case, the
COMPUTE-APPLICABLE-METHODS procedure returns all applicable
methods in no specific order.
(COMPUTE-EFFECTIVE-METHOD LIST1 LIST2) [MOP PROCEDURE]
==> PROCEDURE
LIST1 is a set of applicable methods (see COMPUTE-APPLICABLE-
METHODS) and LIST2 is an (already evaluated) list of arguments
to be passed to one of those methods.
The "effective method" of a set of methods that the most
specific method (the one with the most specific classes in its
specializer) that still matches the classes of the arguments
in LIST2. Consider the following generic:
(define-class foo ())
(define-class bar (foo))
(define-generic frob)
(define-method (frob (x <type>) 0)
(define-method (frob (x bar)) 1)
BAR is more specific than FOO, so the FROB method specializing
in BAR will be selected when LIST2 consists of an instance of
the class BAR. However BAR is too specific to handle instances
of the class FOO, so the method specializing in <TYPE> will be
selected when LIST2 consists of an instance of FOO.
COMPUTE-EFFECTIVE-METHOD finally creates a procedure that
applies arguments of the given types to the selected method.
The resulting procedure binds the symbol CALL-NEXT-METHOD
internally to a procedure that passes the received arguments
to the next-unspecific method. See CALL-NEXT-METHOD for details.
COMPUTE-EFFECTIVE-METHOD returns the procedure described above.
(GENERIC-METHODS GENERIC) ==> LIST [MOP PROCEDURE]
Return the list of methods of the given generic procedure. Note
that methods are not ordinary procedures. In SOS, they are
represented by lists of the form
(specializer procedure)
where SPECIALIZER is the signature of the method and PROCEDURE
an ordinary procedure handling arguments matching the signature.
So to find out what kind of arguments a generic procedure can
handle, you may apply the following procedure to it:
(define (signatures generic)
(map (lambda (sig)
(map class-name sig))
(map car (generic-methods generic))))
(NO-APPLICABLE-METHOD) ==> UNDEFINED [MOP PROCEDURE]
When a generic procedure is applied to a type for which it does
not have a specialized method, NO-APPLICABLE-METHOD is called.
By default this procedure signals an error, but it can be
redefined to handle the "no applicable method" condition
differently:
(define-generic frob)
(frob 17) ==> error ; no applicable method
(define (no-applicable-method)
'default-value)
(frob 17) ==> default-value
Note, though, that redefining NO-APPLICABLE-METHOD will affect
*all* generic procedures, so this should be planned carefully.
(NO-NEXT-METHOD) ==> UNDEFINED [MOP PROCEDURE]
When a method call CALL-NEXT-METHOD and there is no less
specific method (see COMPUTE-EFFECTIVE-METHOD), then the
NO-NEXT-METHOD procedure is invoked. By default it will signal
an error:
(define-class foo (<type>))
(define-generic frob)
(define-method (frob x)
(cons '<type> (call-next-method)))
(define-method (frob (x foo))
(cons 'foo (call-next-method)))
(frob (make-instance foo)) ==> error ; no next method
However, NO-NEXT-METHOD can be redefined to handle the "no next
method" condition differently:
(define (no-next-method)
'(top-of-hierarchy))
(frob (make-instance foo))
==> (foo <type> top-of-hierarchy)
Note, though, that redefining NO-NEXT-METHOD will affect *all*
generic procedures, so this should be planned carefully.
Dynamic MOP Procedures
----------------------
(ADD-METHOD GENERIC LIST PROCEDURE) [MOP PROCEDURE]
==> UNSPECIFIC
ADD-METHOD is a low-level interface for adding a new method to a
generic procedure. GENERIC is the generic procedure to which the
method will be added, LIST is a specializer (see COMPUTE-
APPLICABLE-METHODS), and PROCEDURE is a procedure handling the
types in the specializer.
The first argument of PROCEDURE must be named CALL-NEXT-METHOD,
because it will be used to bind the next-unspecific method of
the generic (see COMPUTE-EFFECTIVE-METHOD). The remaining
arguments must match the specializer.
ADD-METHOD performs little or no sanity checking.
Caveat utilitor!
(MAKE-CLASS SYMBOL LIST <SLOT> ...) ==> CLASS [MOP PROCEDURE]
MAKE-CLASS is a low-level interface for creating a new class.
SYMBOL will name the new class, LIST is a list of superclasses,
and each slot defines a slot name and its default value. See
DEFINE-CLASS for details.
MAKE-CLASS does *not* add a method to INITIALIZE, so the
following example will result in (NO-APPLICABLE-METHOD):
(make-instance (make-class 'foo '()))
To create a class dynamically, use
(let ((foo (make-class 'foo '())))
(add-method initialize
(list foo)
(lambda args #t))
(make-instance foo))
(MAKE-GENERIC) ==> GENERIC [MOP PROCEDURE]
MAKE-GENERIC is a low-level interface for creating a new generic
procedure with no methods.
Class Hierarchy
---------------
The basic S9 SOS class hierarchy consists of the following
classes:
<TYPE>
<INSTANCE>
<CLASS>
<GENERIC>
<BUILT-IN>
<TYPE> is the top of the entire class hierarchy, hence a method
specializing in <TYPE> will match any kind of argument.
<INSTANCE> and <BUILT-IN> are the bases of two disjoint sets of
types, where <INSTANCE> forms the base of the "OOP part" of SOS
and <BUILT-IN> the base of the native Scheme type hierarchy.
Note in particular that this means that a <BUILT-IN> is *not*
an <INSTANCE>, so
(make-instance <integer>)
will *not* create an instance of <INTEGER>.
<CLASS> and <GENERIC> are the only instance classes that are
necessary to make SOS work. This small hierarchy reflects nicely
that both classes and generics are in fact ordinary instances.
Just try
(class-name (class-of <class>))
or (slot-ref initialize 'methods)
The sub-hierarchy of <BUILT-IN> lists the native Scheme data
types. As noted above, these class are abstract and cannot be
used to form valid instances. Their only purpose is to allow
method to specialize in Scheme data types. <BUILT-IN>, the top
of the hierarchy matches any Scheme type.
<BUILT-IN>
<BOOLEAN>
<CHAR>
<EOF-OBJECT>
<NULL>
<NUMBER>
<INTEGER>
<PAIR>
<PORT>
<INPUT-PORT>
<OUTPUT-PORT>
<PROCEDURE>
<ARRAY>
<STRING>
<VECTOR>
<SYMBOL>
The <BUILT-IN> tree contains some subclasses that do not have
direct counterparts in the set of Scheme types, like <NUMBER> or
<ARRAY>. Built-in types are hard-wired into the CLASS-OF
procedure:
(class-of '(a b c)) ==> <pair>
(class-of '#(1 2 3)) ==> <vector>
(class-of '()) ==> <null>
So these types can be used for specializing methods, but no new
subclasses of <BUILT-IN> can be defined at user-level, because
they would not be covered by CLASS-OF.
|