+(define (is-a? obj class)
+ "Return @code{#t} if @var{obj} is an instance of @var{class}, or
+@code{#f} otherwise."
+ (and (memq class (class-precedence-list (class-of obj))) #t))
+
+
+\f
+
+;;;
+;;; Slot access. This protocol is a bit of a mess: there's the `slots'
+;;; slot, which ostensibly holds "slot definitions" but really just has
+;;; specially formatted lists. And then there's the `getters-n-setters'
+;;; slot, which mirrors `slots' but should in theory indicates how to
+;;; get at slots for a particular instance -- never mind that `slots'
+;;; was also computed for a particular instance, and that
+;;; `getters-n-setters' is a strangely structured chain of pairs.
+;;; Perhaps we can fix this in the future, following the CLOS MOP, to
+;;; have proper <effective-slot-definition> objects.
+;;;
+(define (get-slot-value-using-name class obj slot-name)
+ (match (assq slot-name (struct-ref class class-index-getters-n-setters))
+ (#f (slot-missing class obj slot-name))
+ ((name init-thunk . (? exact-integer? index))
+ (struct-ref obj index))
+ ((name init-thunk getter setter . _)
+ (getter obj))))
+
+(define (set-slot-value-using-name! class obj slot-name value)
+ (match (assq slot-name (struct-ref class class-index-getters-n-setters))
+ (#f (slot-missing class obj slot-name value))
+ ((name init-thunk . (? exact-integer? index))
+ (struct-set! obj index value))
+ ((name init-thunk getter setter . _)
+ (setter obj value))))
+
+(define (test-slot-existence class obj slot-name)
+ (and (assq slot-name (struct-ref class class-index-getters-n-setters))
+ #t))
+
+(define (check-slot-args class obj slot-name)
+ (unless (class? class)
+ (scm-error 'wrong-type-arg #f "Not a class: ~S"
+ (list class) #f))
+ (unless (instance? obj)
+ (scm-error 'wrong-type-arg #f "Not an instance: ~S"
+ (list obj) #f))
+ (unless (symbol? slot-name)
+ (scm-error 'wrong-type-arg #f "Not a symbol: ~S"
+ (list slot-name) #f)))
+
+(define (slot-ref-using-class class obj slot-name)
+ (check-slot-args class obj slot-name)
+ (let ((val (get-slot-value-using-name class obj slot-name)))
+ (if (unbound? val)
+ (slot-unbound class obj slot-name)
+ val)))
+
+(define (slot-set-using-class! class obj slot-name value)
+ (check-slot-args class obj slot-name)
+ (set-slot-value-using-name! class obj slot-name value))
+
+(define (slot-bound-using-class? class obj slot-name)
+ (check-slot-args class obj slot-name)
+ (not (unbound? (get-slot-value-using-name class obj slot-name))))
+
+(define (slot-exists-using-class? class obj slot-name)
+ (check-slot-args class obj slot-name)
+ (test-slot-existence class obj slot-name))
+
+;;;
+;;; Before we go on, some notes about class redefinition. In GOOPS,
+;;; classes can be redefined. Redefinition of a class marks the class
+;;; as invalid, and instances will be lazily migrated over to the new
+;;; representation as they are accessed. Migration happens when
+;;; `class-of' is called on an instance. For more technical details on
+;;; object redefinition, see struct.h.
+;;;
+;;; In the following interfaces, class-of handles the redefinition
+;;; protocol. I would think though that there is some thread-unsafety
+;;; here though as the { class, object data } pair needs to be accessed
+;;; atomically, not the { class, object } pair.
+;;;
+
+(define (slot-ref obj slot-name)
+ "Return the value from @var{obj}'s slot with the nam var{slot_name}."
+ (unless (symbol? slot-name)
+ (scm-error 'wrong-type-arg #f "Not a symbol: ~S"
+ (list slot-name) #f))
+ (let* ((class (class-of obj))
+ (val (get-slot-value-using-name class obj slot-name)))
+ (if (unbound? val)
+ (slot-unbound class obj slot-name)
+ val)))
+
+(define (slot-set! obj slot-name value)
+ "Set the slot named @var{slot_name} of @var{obj} to @var{value}."
+ (unless (symbol? slot-name)
+ (scm-error 'wrong-type-arg #f "Not a symbol: ~S"
+ (list slot-name) #f))
+ (set-slot-value-using-name! (class-of obj) obj slot-name value))
+
+(define (slot-bound? obj slot-name)
+ "Return the value from @var{obj}'s slot with the nam var{slot_name}."
+ (unless (symbol? slot-name)
+ (scm-error 'wrong-type-arg #f "Not a symbol: ~S"
+ (list slot-name) #f))
+ (not (unbound? (get-slot-value-using-name (class-of obj) obj slot-name))))
+
+(define (slot-exists? obj slot-name)
+ "Return @code{#t} if @var{obj} has a slot named @var{slot_name}."
+ (unless (symbol? slot-name)
+ (scm-error 'wrong-type-arg #f "Not a symbol: ~S"
+ (list slot-name) #f))
+ (test-slot-existence (class-of obj) obj slot-name))
+
+
+\f
+
+;;;
+;;; Method accessors.
+;;;
+(define (method-generic-function obj)
+ "Return the generic function for the method @var{obj}."
+ (unless (is-a? obj <method>)
+ (scm-error 'wrong-type-arg #f "Not a method: ~S"
+ (list obj) #f))
+ (slot-ref obj 'generic-function))
+
+(define (method-specializers obj)
+ "Return specializers of the method @var{obj}."
+ (unless (is-a? obj <method>)
+ (scm-error 'wrong-type-arg #f "Not a method: ~S"
+ (list obj) #f))
+ (slot-ref obj 'specializers))
+
+(define (method-procedure obj)
+ "Return the procedure of the method @var{obj}."
+ (unless (is-a? obj <method>)
+ (scm-error 'wrong-type-arg #f "Not a method: ~S"
+ (list obj) #f))
+ (slot-ref obj 'procedure))
+
+
+\f
+
+;;;
+;;; Generic functions!
+;;;