#
Chapter 4
`class.ss`: Classes and Objects

A class specifies

- a collection of fields;

- a collection of methods;

- initial value expressions for the fields; and

- initialization variables that are bound to initialization arguments.

An object is a collection of bindings for fields that are instantiated according to a class description.

The primary role of the object system is ability to define a new class (a derived class) in terms of an existing class (the superclass) using inheritance and overriding:

- inheritance: An object of a derived class supports methods and instantiates fields declared by the derived class's superclass, as well as methods and fields declared in the derived class expression.

- overriding: A method declared in a superclass can be redeclared in the derived class. References to the overridden method in the superclass use the implementation in the derived class.

An interface is a collection of method names to be implemented by a class, combined with a derivation requirement. A class implements an interface when it

- declares (or inherits) a public method for each variable in the interface;

- is derived from the class required by the interface, if any; and

- specifically declares its intention to implement the interface.

A class can implement any number of interfaces. A derived class automatically implements any interface that its superclass implements. Each class also implements an implicitly-defined interface that is associated with the class. The implicitly-defined interface contains all of the class's public method names, and it requires that all other implementations of the interface are derived from the class.

A new interface can extend one or more interfaces with additional method names; each class that implements the extended interface also implements the original interfaces. The derivation requirements of the original interface must be consistent, and the extended interface inherits the most specific derivation requirement from the original interfaces.

Classes, objects, and interfaces are all first-class Scheme values. However, a MzScheme class or interface is not a MzScheme object (i.e., there are no ``meta-classes'' or ``meta-interfaces'').

## 4.1 Object Example

The following example conveys the object system's basic style.

    (define stack<%> (interface () push! pop! none?))

    (define stack%
      (class* object% (stack<%>)
        ; Declare public methods:
        (public push! pop! none? print-name)

        (define stack null)        ; A private field
        (init-field (name 'stack)) ; A public field

        ; Method implementations:
        (define (push! v) (set! stack (cons v stack)))
        (define (pop!)
          (let ([v (car stack)])
             (set! stack (cdr stack))
             v))
        (define (none?) (null? stack))
        (define (print-name) (display name) (newline))

        ; Call superclass initializer:
        (super-instantiate ())))

    (define fancy-stack%
      (class stack%
        ; Declare override
        (override print-name)

        ; Add inherited field to local environment
        (inherit-field name)

        (define (print-name)
          (display name)
          (display ", Esq.")
          (newline))

        (super-instantiate ())))

    (define double-stack%
      (class stack%
        (inherit push!)

        (public double-push!)
        (define (double-push! v) (push! v) (push! v))

        ; Always supply name
        (super-instantiate () (name 'double-stack))))

    (define-values (make-safe-stack-class is-safe-stack?)
      (let ([safe-stack<%> (interface (stack<%>))])
        (values
         (lambda (super%)
           (class* super% (safe-stack<%>)
             (inherit none?)
             (rename [std-pop! pop!])
             (override pop!)
             (define (pop!) (if (none?) #f (std-pop!)))
             (super-instantiate ())))
         (lambda (obj)
           (is-a? obj safe-stack<%>)))))

    (define safe-stack% (make-safe-stack-class stack%))

The interface `stack<%>`1 defines the ever-popular stack interface with the methods `push!`, `pop!`, and `none?`. Since it has no superinterfaces, the only derivation requirement of `stack<%>` is that its classes are derived from the built-in empty class, `object%`. The class `stack%`2 is derived from `object%` and implements the `stack<%>` interface. Three additional classes are derived from the basic `stack%` implementation:

- The class `fancy-stack%` defines a stack that overrides `print-name` to add an ``Esq.'' suffix.

- The class `double-stack%` extends the functionality `stack%` with a new method, `double-push!`. It also supplies a specific `name` to `stack%`.

- The class `safe-stack%` overrides the `pop!` method of `stack%`, ensuring that `#f` is returned whenever the stack is empty.

In each derived class, the call `(super-instantiate `...`)` causes the superclass portion of the object to be initialized, including the initialization of its fields.

The creation of `safe-stack%` illustrates the use of classes as first-class values. Applying `make-safe-stack-class` to `named-stack%` or `double-stack%` -- indeed, any class with `push`, `pop!`, and `none?` methods -- creates a ``safe'' version of the class. A stack object can be recognized as a safe stack by testing it with `is-safe-stack?`; this predicate returns `#t` only for instances of a class created with `make-safe-stack-class` (because only those classes implement the `safe-stack<%>` interface).

In each of the example classes, the field `name` contains the name of the class. The `name` instance variable is introduced as a new instance variable in `stack%`, and it is declared there with the `init-field` keyword, which means that an instantiation of the class can specify the initial value, but it defaults to `'stack`. The `double-stack%` class provides `name` when initializing the `stack%` part of the object, so a name cannot be supplied when instantiating `double-stack%`. When the `print-name` method of an object from `double-stack%` is invoked, the name printed to the screen is always ``double-stack''.

While all of `named-stack%`, `double-stack%`, and `safe-stack%` inherit the `push!` method of `stack%`, it is declared with `inherit` only in `double-stack%`; new declarations in `named-stack%` and `safe-stack%` do not need to refer to `push!`, so the inheritance does not need to be declared. Similarly, only `safe-stack%` needs to declare `(inherit none?)`.

The `safe-stack%` class overrides `pop!` to extend the implementation of `pop!`. The new definition of `pop!` must access the original `pop!` method that is defined in `stack%`. The `rename` declaration binds a new name, `std-pop!` to the original `pop!`. Then, `std-pop!` is used in the overriding `pop!`. Variables declared with `rename` cannot be overridden, so `std-pop!` will always refer to the superclass's `pop!`.

The `instantiate` form and ``make-object`` procedure both create an object from a class. The `instantiate` form supports initialization arguments by both position and name, while ``make-object`` supports initialization arguments by position only. The following examples create objects using the classes above:

    (define stack (make-object stack%))
    (define fred (make-object stack% 'Fred))
    (define joe (instantiate stack% () (name 'Joe)))
    (define double-stack (make-object double-stack%))
    (define safe-stack (instantiate safe-stack% () (name 'safe)))

The `send` form calls a method on an object, finding the method by name. The following example uses the objects created above:

    (send stack push! fred)
    (send stack push! double-stack)
    (let loop ()
      (if (not (send stack none?))
        (begin
          (send (send stack pop!) print-name)
          (loop))))

This loop displays `'double-stack` and `'Fred` to the standard output port.

## 4.2 Creating Interfaces

The `interface` form creates a new interface:

    (interface (super-interface-expr ···) variable ···)

All of the `variable`s must be distinct.

Each `super-interface-expr` is evaluated (in order) when the `interface` expression is evaluated. The result of each `super-interface-expr` must be an interface value, otherwise the `exn:object` exception is raised. The interfaces returned by the `super-interface-expr`s are the new interface's superinterfaces, which are all extended by the new interface. Any class that implements the new interface also implements all of the superinterfaces.

The result of an `interface` expression is an interface that includes all of the specified `variable`s, plus all variables from the superinterfaces. Duplicate variable names among the superinterfaces are ignored, but if a superinterfaces contains one of the `variable`s in the `interface` expression, the `exn:object` exception is raised.

If no `super-interface-expr`s are provided, then the derivation requirement of the resulting interface is trivial: any class that implements the interface must be derived from `object%`. Otherwise, the implementation requirement of the resulting interface is the most specific requirement from its superinterfaces. If the superinterfaces specify inconsistent derivation requirements, the `exn:object` exception is raised.

## 4.3 Creating Classes

The built-in class `object%` has no methods fields, implements only its own interface, `(`class->interface` object%)`. All other classes are derived from `object%`.

The `class*/names` form creates a new class:

    (class*/names local-names superclass-expr (interface-expr ···)
      class-clause
      ···)

    local-names is one of
      (this-variable)
      (this-variable super-instantiate-variable)
      (this-variable super-instantiate-variable super-make-object-variable)

    class-clause is one of
      (init init-declaration ···)
      (init-field init-declaration ···)
      (field field-declaration ···)
      (inherit-field optionally-renamed-variable ···)
      (init-rest variable)
      (init-rest)
      (public optionally-renamed-variable ···)
      (override optionally-renamed-variable ···)
      (public-final optionally-renamed-variable ···)
      (override-final optionally-renamed-variable ···)
      (private variable ···)
      (inherit optionally-renamed-variable ···)
      (rename renamed-variable ···)
      method-definition
      definition
      expr
      (begin class-clause ···)

    init-declaration is one of
      variable
      (optionally-renamed-variable)
      (optionally-renamed-variable default-value-expr)

    field-declaration is
      (optionally-renamed-variable default-value-expr)

    optionally-renamed-variable is one of
      variable
      renamed-variable

    renamed-variable is
      (internal-variable external-variable)

    method-definition is
      (define-values (variable) method-procedure)

    method-procedure is
      (lambda formals expr ···1)
      (case-lambda (formals expr ···1) ···)
      (let-values (((variable) method-procedure) ···) method-procedure)
      (letrec-values (((variable) method-procedure) ···) method-procedure)
      (let-values (((variable) method-procedure) ···1) variable)
      (letrec-values (((variable) method-procedure) ···1) variable)

The `this-variable`, `super-instantiate-variable`, and `super-make-object-variable` variables (usually `this`, `super-instantiate`, and `super-make-object`) are bound in the rest of the `class*/names` expression, excluding `superclass-expr` and the `interface-expr`s. In instances of the new class, `this-variable` (i.e., `this`) is bound to the object itself; `super-instantiate-variable` (i.e., `super-instantiate`) is bound to a form that must be used (once) to initialize fields in the superclass (see section 4.4); `super-make-object-variable` (i.e., `super-make-object`) can be used instead of `super-instantiate-variable` to initialize superclass fields. See section 4.4 for more information about `super-instantiate-variable` and `super-make-object-variable`.

The `superclass-expr` expression is evaluated when the `class*/names` expression is evaluated. The result must be a class value (possibly `object%`), otherwise the `exn:object` exception is raised. The result of the `superclass-expr` expression is the new class's superclass.

The `interface-expr` expressions are also evaluated when the `class*/names` expression is evaluated, after `superclass-expr` is evaluated. The result of each `interface-expr` must be an interface value, otherwise the `exn:object` exception is raised. The interfaces returned by the `interface-expr`s are all implemented by the class. For each variable in each interface, the class (or one of its ancestors) must declare a public instance variable with the same name, otherwise the `exn:object` exception is raised. The class's superclass must satisfy the implementation requirement of each interface, otherwise the `exn:object` exception is raised.

The `class-clause`s define initialization arguments, public and private fields, and public and private methods. For each `variable` or `optionally-renamed-variable` in a `public`, `override`, `public-final`, `override-final`, or `private` clause, there must be one `method-definition`. All other definition `class-clause`s create private fields. All remaining `expr`s are initialization expressions to be evaluated when the class is instantiated (see section 4.4).

The result of a `class*/names` expression is a new class, derived from the specified superclass and implementing the specified interfaces. Instances of the class are created with the `instantiate` form or `make-object` procedure, as described in section 4.4. Debugging access to the class is controlled by the parent of the current inspector (see section 4.5 in PLT MzScheme: Language Manual).

Each `class-clause` is (partially) macro-expanded to reveal its shapes. If a `class-clause` is a `begin` expression, its sub-expressions are lifted out of the `begin` and treated as `class-clause`s, in the same way that `begin` is flattened for top-level and embedded definitions.

The `class*` form is like `class*/names`, but omits `local-names` and always uses the name ``this``, `super-instantiate`, and ``super-make-object``:

    (class* superclass-expr (interface-expr ···)
      class-clause
      ···)

The `class` form further omits the `interface-expr`s, for the case that none are needed:

    (class superclass-expr
      class-clause
      ···)

The `public*`, `public-final*`, `override*`, `override-final*`, and `private*` forms abbreviate a `public`, `public-final`, `override`, `override-final`, or `private` declaration and a sequence of definitions:

     (public* (name expr) ···)
    =expands=>
     (begin
      (public name ···)
      (define name expr) ···)

    etc.

The `define/public`, `define/public-final`, `define/override`, `define/override-final`, and `define/private` forms similarly abbreviate a `public`, `override`, or `private` declaration with a definition:

     (define/public name expr)
    =expands=>
     (begin
      (public name)
      (define name expr))

     (define/public (name . formals) expr)
    =expands=>
     (begin
      (public name)
      (define (name . formals) expr))

    etc.

### 4.3.1 Initialization Variables

A class's initialization variables, declared with `init`, `init-field`, and `init-rest`, are instantiated for each object of a class. Initialization variables can be used in the initial value expressions of fields, default value expressions for initialization arguments, and in initialization expressions. Only initialization variables declared with `init-field` can be accessed from methods; accessing any other initialization variable from a method is a syntax error.

The values bound to initialization variables are

- the arguments provided with `instantiate` or passed to `make-object`, if the object is created as a direct instance of the class; or,

- the arguments passed to the superclass initialization form or procedure, if the object is created as an instance of a derived class.

If an initialization argument is not provided for a initialization variable that has an associated `default-value-expr`, then the `default-value-expr` expression is evaluated to obtain a value for the variable. A `default-value-expr` is only evaluated when an argument is not provided for its variable. The environment of `default-value-expr` includes all of the initialization variables, all of the fields, and all of the methods of the class. If multiple `default-value-expr`s are evaluated, they are evaluated from left to right. Object creation and field initialization are described in detail in section 4.4.

If an initialization variable has no `default-value-expr`, then the object creation or superclass initialization call must supply an argument for the variable, otherwise the `exn:object` exception is raised.

Initialization arguments can be provided by name or by position. The external name of an initialization variable can be used with `instantiate` or with the superclass initialization form. Those forms also accept by-position arguments. The `make-object` procedure and the superclass initialization procedure accept only by-position arguments.

Arguments provided by position are converted into by-name arguments using the order of `init` and `init-field` clauses and the order of variables within each clause. When a `instantiate` form provides both by-position and by-name arguments, the converted arguments are placed before by-name arguments. (The order can be significant; see also section 4.4.)

Unless a class contains an `init-rest` clause, when the number of by-position arguments exceeds the number of declared initialization variables, the order of variables in the superclass (and so on, up the superclass chain) determines the by-name conversion.

If a class expression contains an `init-rest` clause, there must be only one, and it must be last. If it declares a variable, then the variable receives extra by-position initialization arguments as a list (similar to a dotted ``rest argument'' in a procedure). An `init-rest` variable can receive by-position initialization arguments that are left over from a by-name conversion for a derived class. When a derived class's superclass initialization provides even more by-position arguments, they are prefixed onto the by-position arguments accumulated so far.

If too few or too many by-position initialization arguments are provided to an object creation or superclass initialization, then the `exn:object` exception is raised. Similarly, if extra by-position arguments are provided to a class with an `init-rest` clause, the `exn:object` exception is raised.

Unused (by-name) arguments are be propagated to the superclass, as described in section 4.4. Multiple initialization arguments can use the same name if the class derivation contains multiple declarations (in different classes) of initialization variables with the name. See section 4.4 for further details.

See also section 4.3.3.3 for information about internal and external names.

### 4.3.2 Fields

Each `field`, `init-field`, and non-method `define-values` clause in a class declares one or more new fields for the class. Fields declared with `field` or `init-field` are public. Public fields can be accessed and mutated by subclasses using `inherit-field`. Public fields are also accessible outside the class via `class-field-accessor` and mutable via `class-field-mutator` (see section 4.5). Fields declared with `define-values` are accessible only within the class.

A field declared with `init-field` is both a public field an an initialization variable. See section 4.3.1 for information about initialization variables.

An `inherit-field` declaration makes a public field defined by a superclass directly accessible in the class expression. If the indicated field is not defined in the superclass, the `exn:object` exception is raised when the class expression is evaluated. Every field in a superclass is present in a derived class, even if it is not declared with `inherit-field` in the derived class. The `inherit-field` clause does not control inheritance, but merely controls lexical scope within a class expression.

When an object is first created, all of its fields have the undefined value (see section 3.1 in PLT MzScheme: Language Manual). The fields of a class are initialized at the same time that the class's initialization expressions are evaluated; see section 4.4 for more information.

See also section 4.3.3.3 for information about internal and external names.

### 4.3.3 Methods

#### 4.3.3.1 Method Definitions

Each `public`, `override`, `public-final`, `override-final`, and `private` clause in a class declares one or more method names. Each method name must have a corresponding `method-definition`. The order of `public`, `override`, `public-final`, `override-final`, `private` clauses and their corresponding definitions (among themselves, and with respect to other clauses in the class) does not matter.

As shown in section 4.3, a method definition is syntactically restricted to certain procedure forms, as defined by the grammar for `method-procedure`; in the last two forms of `method-procedure`, the body `variable` must be one of the `variable`s bound by `let-values` or `letrec-values`. A `method-procedure` expression is not evaluated directly. Instead, for each method, a class-specific method procedure is created; it takes an initial object argument, in addition to the arguments the procedure would accept if the `method-procedure` expression were evaluated directly. The body of the procedure is transformed to access methods and fields through the object argument.

A method declared with `public` or `public-final` introduces a new method into a class. The method must not be present already in the superclass, otherwise the `exn:object` exception is raised when the class expression is evaluated. A method declared with `public-final` cannot be overridden in a subclass.

A method declared with `override` or `override-final` overrides a definition already present in the superclass. If the method is not already present, the `exn:object` exception is raised when the class expression is evaluated. A method declared with `override-final` cannot be overridden in a subclass.

A method declared with `private` is not accessible outside the class expression, cannot be overridden, and never overrides a method in the superclass.

#### 4.3.3.2 Inherited and Superclass Methods

Each `inherit` and `rename` clause declares one or more methods that are not defined in the class, but must be present in the superclass. Methods declared with `inherit` are subject to overriding, while methods declared with `rename` are not. Methods that are present in the superclass but not declared with `inherit` or `rename` are not directly accessible in the class (through they can be called with `send`).

Every public method in a superclass is present in a derived class, even if it is not declared with `inherit` in the derived class. The `inherit` clause does not control inheritance, but merely controls lexical scope within a class expression.

If a method declared with `inherit` is not present in the superclass, the `exn:object` exception is raised when the class expression is evaluated.

#### 4.3.3.3 Internal and External Names

Each method declared with `public`, `override`, `public-final`, `override-final`, `inherit`, and `rename` can have separate internal and external names when `(internal-variable external-variable)` is used for declaring the method. The internal name is used to access the method directly within the class expression, while the external name is used with `send` and `generic` (see section 4.5). If a single `variable` is provided for a method declaration, the variable is used for both the internal and external names.

Method inheritance and overriding are based external names, only. Separate internal and external names are required for `rename`, because its purpose is to provide access to the superclass's version of an overridden method.

Each `init`, `init-field`, `field`, or `inherit-field` variable similarly has an internal and an external name. The internal name is used within the class to access the variable, while the external name is used outside the class when providing initialization arguments (e.g., to `instantiate`), inheriting a field, or accessing a field externally (e.g., with `class-field-accessor`). As for methods, when inheriting a field with `inherit-field`, the external name is matched to an external field name in the superclass, while the internal name is bound in the `class` expression.

A single identifier can be used as an internal variable and an external variable, and it is possible to use the same identifier as internal and external variables for different bindings. Furthermore, within a single class, a single name can be used as an external method name, an external field name, and an external initialization argument name. Overall, the set of all internal variables must be distinct, and set of of external variables must be distinct for each of the method, field, and initialization-argument categories.

By default, external names have no lexical scope, which means, for example, that an external method name matches the same syntactic symbol in all uses of `send`. The `define-local-member-name` form introduces a set of scoped external names:

    (define-local-member-name variable ···)

This form binds each `variable` so that, within the scope of the definition, each use of each `variable` as an external name is resolved to a hidden name generated by the `define-local-member-name` declaration. Thus, methods, fields, and initialization arguments declared with such external-name `variable`s are accessible only in the scope of the `define-local-member-name` declaration.

The binding introduced by `define-local-member-name` is a syntax binding that can be exported and imported with modules (see section 5 in PLT MzScheme: Language Manual). Each execution of a `define-local-member-name` declaration generates a distinct hidden name. The `interface->method-names` procedure (see section 4.6) does not expose hidden names.

Example:

    (define o (let ()
                (define-local-member-name m)
                (define c% (class object%
                             (define/public (m) 10)
                             (super-make-object))
                (define o (make-object c%))

                (send o m) ; => 10
                o))

    (send o m) ; => error: no method m

## 4.4 Creating Objects

The `make-object` procedure creates a new object with by-position initialization arguments:

`(make-object``` `class init-v``` `···``)`

An instance of `class` is created, and the `init-v`s are passed as initialization arguments, bound to the initialization variables of `class` for the newly created object as described in section 4.3.1. If `class` is not a class, the `exn:application:type` exception is raised.

The `instantiate` form creates a new object with both by-position and by-name initialization arguments:

    (instantiate class-expr (by-pos-expr ···) (variable by-name-expr) ···)

An instance of the value of `class-expr` is created, and the values of the `by-pos-expr`s are provided as by-position initialization arguments. In addition, the value of each `by-name-expr` is provided as a by-name argument for the corresponding `variable`.

All fields in the newly created object are initially bound to the special undefined value (see section 3.1 in PLT MzScheme: Language Manual). Initialization variables with default value expressions (and no provided value) are also initialized to undefined. After argument values are assigned to initialization variables, expressions in `field` clauses, `init-field` clauses with no provided argument, `init` clauses with no provided argument, private field definitions, and other expressions are evaluated. Those expressions are evaluated as they appear in the class expression, from left to right.

Sometime during the evaluation of the expressions, superclass-declared initializations must be executed once by invoking the form bound to `super-instantiate-variable` (usually `super-instantiate`):

    (super-instantiate-variable (by-position-super-init-expr ···) (variable by-name-super-init-expr ···) ···)

or by calling the procedure bound to `super-make-object-variable` (usually ``super-make-object``):

    (super-make-object-variable super-init-v ···)

The `by-position-super-init-expr`s, `by-name-super-init-exp`s, and `super-init-v`s are mapped to initialization variables in the same way as for `instantiate` and ``make-object``.

By-name initialization arguments to a class that have no matching initialization variable are implicitly added as by-name arguments to a `super-instantiate-variable` or `super-make-object-variable` invocation, after the explicit arguments. If multiple initialization arguments are provided for the same name, the first (if any) is used, and the unused arguments are propagated to the superclass. (Note that converted by-position arguments are always placed before explicit by-name arguments.) The initialization procedure for the `object%` class accepts zero initialization arguments; if it receives any by-name initialization arguments, then `exn:object` exception is raised.

Fields inherited from a superclass will not be initialized until the superclass's initialization procedure is invoked. In contrast, all methods are available for an object as soon as the object is created; the overriding of methods is not affect by initialization (unlike objects in C++).

It is an error to reach the end of initialization for any class in the hierarchy without invoking superclasses initialization; the `exn:object` exception is raised in such a case. Also, if superclass initialization is invoked more than once, the `exn:object` exception is raised.

## 4.5 Field and Method Access

In expressions within a class definition, the initialization variables, fields, and methods of the class all part of the environment, as are the names bound to `super-instantiate-variable` and `super-make-object-variable`. Within a method body, only the fields and other methods of the class can be referenced; a reference to any other class-introduced identifier is a syntax error. Elsewhere within the class, all class-introduced identifiers are available, and fields and initialization variables can be mutated with `set!`.

### 4.5.1 Methods

Method names within a class can only be used in the procedure position of an application expression; any other use is a syntax error. To allow methods to be applied to lists of arguments, a method application can have the form

    (method-variable arg-expr ··· . arg-list-expr)

which calls the method in a way analogous to `(`apply` method-variable arg-expr `···` arg-list-expr)`. The `arg-list-expr` must not be a parenthesized expression, otherwise the dot and the parentheses will cancel each other.

Methods are called from outside a class with the `send` and `send/apply` forms:

    (send obj-expr method-name arg-expr ···)
    (send obj-expr method-name arg-expr ··· . arg-list-expr)
    (send/apply obj-expr method-name arg-expr ··· arg-list-expr)

where the last two forms apply the method to a list of argument values; in the second form, `arg-list-expr` cannot be a parenthesized expression. For any `send` or `send/apply`, if `obj-expr` does not produce an object, the `exn:application:type` exception is raised. If the object has no public method `method-name`, the `exn:object` exception is raised.

The `send*` form calls multiple methods of an object in the specified order:

    (send* obj-expr msg ···)

    msg is one of
      (method-name arg-expr ···)
      (method-name arg-expr ··· . arg-list-expr)

where `arg-list-expr` is not a parenthesized expression.

Example:

    (send* edit (begin-edit-sequence)
                (insert "Hello")
                (insert #\newline)
                (end-edit-sequence))

which is the same as

    (let ([o edit])
      (send o begin-edit-sequence)
      (send o insert "Hello")
      (send o insert #\newline)
      (send o end-edit-sequence))

The `with-method` form extracts a method from an object and binds a local name that can be applied directly (in the same way as declared methods within a class):

    (with-method ((variable (object-expr method-name)) ···)
      expr ···1)

Example:

    (let ([s (make-object stack%)])
      (with-method ([push (s push!)]
                    [pop (s pop!)])
        (push 10)
        (push 9)
        (pop)))

which is the same as

    (let ([s (make-object stack%)])
      (send s push! 10)
      (send s push! 9)
      (send s pop!))

### 4.5.2 Fields

Fields are accessed from outside an object through a field accessor or mutator procedure produced by `class-field-accessor` or `class-field-mutator`:

- `(class-field-accessor class-expr field-name)` returns an accessor procedure that takes an instance of the class produced by `class-expr` and returns the value of the object's `field-name` field.

- `(class-field-mutator class-expr field-name)` returns an mutator procedure that takes an instance of the class produced by `class-expr` and a new value for the field, mutates the field in the object named by `field-name`, then returns void.

### 4.5.3 Generics

A generic can be used instead of a method name to avoid the cost of relocating a method by name within a class. The `make-generic` procedure and `generic` form create generics:

- `(make-generic``` `class-or-interface symbol``)` returns a generic that works on instances of `class-or-interface` (or an instance of a class/interface derived from `class-or-interface`) to call the method named by `symbol`.

  If `class-or-interface` does not contain a method with the (external and non-scoped) name `symbol`, the `exn:object` exception is raised.

- `(generic class-or-interface-expr name)` is analogous to `(make-generic `class-or-interface-expr` '`name`)`, except that `name` can be a scoped method name declared by `define-local-member-name` (see section 4.3.3.3).

A generic is applied with `send-generic`:

    (send-generic obj-expr generic-expr arg-expr ···)
    (send-generic obj-expr generic-expr arg-expr ··· . arg-list-expr)

where the value of `obj-expr` is an object and the value of `generic-expr` is a generic.

## 4.6 Object, Class, and Interface Utilities

`(object?``` `v``)` returns `#t` if `v` is a object, `#f` otherwise.

`(class?``` `v``)` returns `#t` if `v` is a class, `#f` otherwise.

`(interface?``` `v``)` returns `#t` if `v` is an interface, `#f` otherwise.

`(object->vector``` `object``` [`opaque-v`]`)` returns a vector representing `object` that shows its inspectable fields, analogous to `struct->vector` (see section 4.8 in PLT MzScheme: Language Manual).

`(class->interface``` `class``)` returns the interface implicitly defined by `class`.

`(object-interface``` `object``)` returns the interface implicitly defined by the class of `object`.

`(is-a?``` `v interface``)` returns `#t` if `v` is an instance of a class that implements `interface`, `#f` otherwise.

`(is-a?``` `v class``)` returns `#t` if `v` is an instance of `class` (or of a class derived from `class`), `#f` otherwise.

`(subclass?``` `v class``)` returns `#t` if `v` is a class derived from (or equal to) `class`, `#f` otherwise.

`(implementation?``` `v interface``)` returns `#t` if `v` is a class that implements `interface`, `#f` otherwise.

`(interface-extension?``` `v interface``)` returns `#t` if `v` is an interface that extends `interface`, `#f` otherwise.

`(method-in-interface?``` `symbol interface``)` returns `#t` if `interface` (or any of its ancestor interfaces) defines an instance variable with the name `symbol`, `#f` otherwise.

`(interface->method-names``` `interface``)` returns a list of symbols for the instance variable names in `interface` (including instance variables inherited from superinterfaces).

`(object-info``` `object``)` returns two values, analogous to the return values of `struct-info` (see section 4.5 in PLT MzScheme: Language Manual):

- `class`: a class or `#f`; the result is `#f` if the current inspector does not control any class for which the `object` is an instance.

- `skipped?`: `#f` if the first result corresponds to the most specific class of `object`, `#t` otherwise.

`(class-info``` `class``)` returns seven values, analogous to the return values of `struct-type-info` (see section 4.5 in PLT MzScheme: Language Manual):

- `name-symbol`: the class's name as a symbol;

- `field-k`: the number of fields (public and private) defined by the class;

- `field-name-list`: a list of symbols corresponding to the class's public fields; this list can be larger than `field-k` because it includes inherited fields;

- `field-accessor-proc`: an accessor procedure for obtaining field values in instances of the class; the accessor takes an instance and a field index between `0` (inclusive) and `field-k` (exclusive);

- `field-mutator-proc`: a mutator procedure for mmodifying field values in instances of the class; the mutator takes an instance, a field index between `0` (inclusive) and `field-k` (exclusive), and a new field value;

- `super-class`: a class for the most specific ancestor of the given class that is controlled by the current inspector, or `#f` if no ancestor is controlled by the current inspector;

- `skipped?`: `#f` if the sixth result is the most specific ancestor class, `#t` otherwise.

1 A bracketed percent sign (```<%>`'') is used by convention in MzScheme to indicate that a variable's value is a interface.

2 A percent sign (```%`'') is used by convention in MzScheme to indicate that a variable's value is a class.