# (lispkit object)

Library `(lispkit object)` implements a simple, delegation-based object system for LispKit. It provides procedural and declarative interfaces for objects and classes. The class system is optional. It mostly provides means to define and manage new object types and construct objects using object constructors.

## Introduction

Similar to other Scheme and Lisp-based object systems, methods of objects are defined in terms of object/class-specific specializations of generic procedures. A generic procedure consists of methods for the various objects/classes it supports. A generic procedure performs a dynamic dispatch on the first parameter (the `self` parameter) to determine the applicable method.

### Generic procedures

Generic procedures can be defined using the `define-generic` form. Here is an example which defines three generic methods, one with only a `self` parameter, and two with three parameters `self`, `x` and `y`. The last generic procedure definition includes a `default` method which is applicable to all objects for which there is no specific method. When a generic procedure without default is applied to an object that does not define its own method implementation, an error gets signaled.

```scheme
(define-generic (point-coordinates self))
(define-generic (set-point-coordinates! self x y))
(define-generic (point-move! self x y)
  (let ((coord (point-coordinate self)))
    (set-point-coordinate! self (+ (car coord) x) (+ (cdr coord) y))))
```

### Objects

An object encapsulates a list of methods each implementing a generic procedure. These methods are regular closures which can share mutable state. Objects do not have an explicit notion of a field or slot as in other Scheme or Lisp-based object systems. Fields/slots need to be implemented via generic procedures and method implementations sharing state. Here is an example explaining this approach:

```scheme
(define (make-point x y)
  (object ()
    ((point-coordinates self) (cons x y))
    ((set-point-coordinates! self nx ny) (set! x nx) (set! y ny))
    ((object->string self) (string-append (object->string x) "/" (object->string y)))))
```

This is a function creating new point objects. The `x` and `y` parameters of the constructor function are used for representing the state of the point object. The created point objects implement three generic procedures: `point-coordinates`, `set-point-coordinates`, and `object->string`. The latter procedure is defined directly by the library and, in general, used for creating a string representation of any object. By implementing the `object->string` method, the behavior gets customized for the object.

The following lines of code illustrate how point objects can be used:

```scheme
(define pt (make-point 25 37))
pt                                              => #object:#<box (...)>
(object->string pt)                             => "25/37"
(point-coordinates pt)                          => (25 . 37)
(set-point-coordinates! pt 5 6)
(object->string pt)                             => "5/6"
(point-coordinates pt)                          => (5 . 6)
```

### Inheritance

The LispKit object system supports inheritance via delegation. The following code shows how colored points can be implemented by delegating all point functionality to the previous implementation and by simply adding only color-related logic.

```scheme
(define-generic (point-color self) #f)
(define (make-colored-point x y color)
  (object ((super (make-point x y)))
    ((point-color self) color)
    ((object->string self)
       (string-append (object->string color) ":" (invoke (super object->string) self)))))
```

The object created in function `make-colored-point` inherits all methods from object `super` which gets set to a new point object. It adds a new method to generic procedure `point-color` and redefines the `object->string` method. The redefinition is implemented in terms of the inherited `object->string` method for points. The form `invoke` can be used to refer to overridden methods in delegatee objects. Thus, `(invoke (super object->string) self)` calls the `object->string` method of the `super` object but with the identity (`self`) of the colored point.

The following interaction illustrates the behavior:

```scheme
(define cpt (make-colored-point 100 50 'red))
(point-color cpt)                               => red
(point-coordinates cpt)                         => (100 . 50)
(set-point-coordinates! cpt 101 51)
(object->string cpt)                            => "red:101/51"
```

Objects can delegate functionality to multiple delegatees. The order in which they are listed determines the methods which are being inherited in case there are conflicts, i.e. multiple delegatees implement a method for the same generic procedure.

### Classes

Classes add syntactic sugar, simplying the creation and management of objects. They play the following role in the object-system of LispKit:

1. A class defines a constructor for objects represented by this class.
2. Each class defines an object type, which can be used to distinguish objects created by the same constructor and supporting the same methods.
3. A class can inherit functionality from several other classes, making it easy to reuse functionality.
4. Classes are first-class objects supporting a number of class-related procedures.

The following code defines a `point` class with similar functionality as above:

```scheme
(define-class (point x y) ()
  (object ()
    ((point-coordinates self) (cons x y))
    ((set-point-coordinates! self nx ny) (set! x nx) (set! y ny))
    ((object->string self) (string-append (object->string x) "/" (object->string y)))))
```

Instances of this class are created by using the generic procedure `make-instance` which is implemented by all class objects:

```scheme
(define pt2 (make-instance point 82 10))
pt2                                             => #point:#<box (...)>
(object->string pt2)                            => "82/10"
```

Each object created by a class implements a generic procedure `object-class` referring to the class of the object. Since classes are objects themselves we can obtain their name with generic procedure `class-name`:

```scheme
(object-class pt2)                              => #class:#<box (...)>
(class-name (object-class pt2))                 => point
(instance-of? point pt2)                        => #t
(instance-of? point pt)                         => #f
```

Generic procedure `instance-of?` can be used to determine whether an object is a direct or indirect instance of a given class. The last two lines above show that `pt2` is an instance of `point`, but `pt` is not, even though it is functionally equivalent.

The following definition re-implements the colored point example from above using a class:

```scheme
(define-class (colored-point x y color) (point)
  (if (or (< x 0) (< y 0))
      (error "coordinates are negative: ($0; $1)" x y))
  (object ((super (make-instance point x y)))
    ((point-color self) color)
    ((object->string self)
       (string-append (object->string color) ":" (invoke (super object->string) self)))))
```

The following lines illustrate the behavior of `colored-point` objects vs `point` objects:

```scheme
(point-color cpt2)                              => blue
(point-coordinates cpt2)                        => (128 . 256)
(set-point-coordinates! cpt2 64 32)
(object->string cpt2)                           => "blue:64/32"
(instance-of? point cpt2)                       => #t
(instance-of? colored-point cpt2)               => #t
(instance-of? colored-point cpt)                => #f
(class-name (object-class cpt2))                => colored-point
```

## Procedural object interface

**object-type-tag** <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-bdc0997c38ced7c944ea089918006133f1a4052f%2Fconst.png?alt=media" alt="" data-size="line">

Symbol representing the `object` type. The `type-for` procedure of library `(lispkit type)` returns this symbol for all objects created via `object` or `make-object`.

**(object?&#x20;*****obj*****)** <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

Returns `#t` if *obj* is an object as defined by this library. Objects are either created procedurally via `make-object` or declaratively via `object`.

**(make-object)** <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">\
\&#xNAN;**(make-object&#x20;*****delegate ...*****)**

**(method&#x20;*****obj generic*****)** <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

**(object-methods&#x20;*****obj*****)** <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

**(add-method!&#x20;*****obj generic method*****)** <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

**(delete-method!&#x20;*****obj generic*****)** <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

**(make-generic-procedure&#x20;*****...*****)** <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

## Declarative object interface

**(object ...)** <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-1f16bffbe68f0214f8ffbb3b3230748db5570827%2Fsyntax.png?alt=media" alt="" data-size="line">

**(define-generic ...)** <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-1f16bffbe68f0214f8ffbb3b3230748db5570827%2Fsyntax.png?alt=media" alt="" data-size="line">

**(invoke ...)** <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-1f16bffbe68f0214f8ffbb3b3230748db5570827%2Fsyntax.png?alt=media" alt="" data-size="line">

## Procedural class interface

**class-type-tag** <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-bdc0997c38ced7c944ea089918006133f1a4052f%2Fconst.png?alt=media" alt="" data-size="line">

Symbol representing the `class` type. The `type-for` procedure of library `(lispkit type)` returns this symbol for all class objects.

**(class?&#x20;*****obj*****)** <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

Returns `#t` if *obj* is a class object, `#f` otherwise.

**root**     \[object]

The root class object. All class objects have `root` as its direct or indirect superclass object.

**(make-class&#x20;*****name superclasses constructor*****)** <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-d20368c588cfbb523beb2fae4f8be0f8ef011884%2Fproc.png?alt=media" alt="" data-size="line">

Returns a new class whose name is *name*. *superclasses* is a list of superclass objects. *constructor* is a procedure that is called whenever instances of this new class are being created. *constructor* are passed the arguments passed to `make-instance` when a new object of this class is being created. It returns two values: a list of delegate objects and an initializer procedure which sets up the internal state.

### Instance methods

**(object-class&#x20;*****obj*****)** <img src="https://github.com/objecthub/lisppad-site/blob/gitbook/.gitbook/assets/generic.png" alt="" data-size="line">

Returns the class of object *obj*.

**(object-equal?&#x20;*****obj other*****)** <img src="https://github.com/objecthub/lisppad-site/blob/gitbook/.gitbook/assets/generic.png" alt="" data-size="line">

Returns `#t` if *obj* and *other* are considered equal objects.

**(object->string&#x20;*****obj*****)** <img src="https://github.com/objecthub/lisppad-site/blob/gitbook/.gitbook/assets/generic.png" alt="" data-size="line">

Returns a string representation of object *obj*.

### Class methods

**(class-name&#x20;*****class*****)** <img src="https://github.com/objecthub/lisppad-site/blob/gitbook/.gitbook/assets/generic.png" alt="" data-size="line">

Returns the class name of *class*.

**(class-direct-superclasses&#x20;*****class*****)** <img src="https://github.com/objecthub/lisppad-site/blob/gitbook/.gitbook/assets/generic.png" alt="" data-size="line">

Returns a list of superclass objects of *class*.

**(subclass?&#x20;*****class other*****)** <img src="https://github.com/objecthub/lisppad-site/blob/gitbook/.gitbook/assets/generic.png" alt="" data-size="line">

Returns `#t` if *class* is a subclass of class *other*, `#f` otherwise.

**(make-instance&#x20;*****class arg ...*****)** <img src="https://github.com/objecthub/lisppad-site/blob/gitbook/.gitbook/assets/generic.png" alt="" data-size="line">

Creates and returns a new object of *class*. *arg ...* are the constructor arguments passed to the constructor of *class*.

**(instance-of?&#x20;*****class obj*****)** <img src="https://github.com/objecthub/lisppad-site/blob/gitbook/.gitbook/assets/generic.png" alt="" data-size="line">

Returns `#t` if *obj* is an instance of *class*.

## Declarative class interface

**(define-class&#x20;*****...*****)** <img src="https://1467949168-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fna2foeoaXHYkSD3fhs0t%2Fuploads%2Fgit-blob-1f16bffbe68f0214f8ffbb3b3230748db5570827%2Fsyntax.png?alt=media" alt="" data-size="line">
