The scheme package Object Model


1 - Basic ideas.

The object model of the scheme package is defined as follow:

2 - Predefined methods.

    1 - Methods of the class <class>.

(class define symbol object) 
(class define (symbol ...) ...)
The first form creates in the environment of  'class' a new mapping of  'symbol' with the object 'object'. 'symbol' must not be quoted. 
The second form creates a method. The parameters are the same as for a procedure definition with define
Returns an undefined value.
(class get symbol) The symbol  'symbol' must not be quoted. 
Returns the value of the object named 'symbol' in the environement of  'class'
(class get-parent) Returns the parent class of the class  'class'. It returns <object> applied on <class> and <object>.
(class make) 
(<class> make class (...))
The first form applies to all classes of the system except the class <class> , it creates an instance the class 'class'. The fields are initialised to an undefined value. 
The second form create a new class that is a child of the class 'class'.

    2 - Methods of the class <object>.

(object get-class) Returns the class of the object  'object'. It returns <class> applied on <object> and <class>.
(object super symbol ...) Calls the first precursor method of the method named 'symbol' in the inheritance tree of the object 'object'.

3 - Predefined procedures.

(object? obj) Returns #t if  'obj' is an instance of object, #f otherwise.
(method? obj) Returns #t if  'obj' is a method, #f otherwise. Note that if an object is a method he is also a procedure.
(method L exp ...) Creates a method. It has the same syntax as lambda but returns a method.

4 - Example.

In the following example we define a class <list> that encapsulate some of the functions that applies to Scheme lists.
Notation: The convention is the to write the name of a class beetween '<' and '>', and to put a dot at the beginning of the name of a field. It is just a convention: every symbol can be used.

First, we define the class <list> with fields .head and .size.

(define <list> (<class> make (.head .size)))

Now we can create a list by writing:

(define L (<list> make))

The following statement creates an initialization method. It takes zero or one argument. The argument must be a list.
We can see in this example that fields of the list are variables of the method's current environment.

(<list> define (init . L)
  (cond ((null? L)
         (set! .head '())
         (set! .size 0))
        (else
         (set! .head (car L))
         (set! .size (length L)))))

Here is the initialization of our list:

(L init '(1 3 2 4 1))

We can define a method that displays a readable representation of a list. Note that there is no ambiguity in the body of the method when we call procedure display since methods are defined as a field of the class of the current object.

(<list> define (display)
  (display this))

An other way to do that is:

(<list> define display
  (method ()
    (display this)))

To display our list we can write:

(L display) which produces the output: (1 3 2 4 1)

The next three methods respectively adds an element at the beginning of the list, remove an element and returns the length of the list.

(<list> define (add obj)
  (set! .list (cons obj .list)
  (set! .size (+ .size 1)))

(<list> define (remove)
  (if (not (null? .head))
      (begin
        (set! .head (cdr .head))
        (set! .size (- .size 1)))))

(<list> define (length)
  .size)

This method definition demonstrates an important aspect of the method invocation: 'this' must be used to call the methods of the current object.
It also shows that I can write very inefficient methods ;-).

(<list> define (occurences-of obj)
  (if (= (this length) 0)
      0
      (let ((next ((this get-class) make)))
        (next init (cdr .head))
        (if (equal? obj (car .head))
            (+ 1 (next occurences-of obj))
            (next occurences-of obj)))))

Methods can be called in a functional way: the first statement gets the value of the field 'number-of' of the class <list>, the next shows how to call this method in a functional way on our previously created list and the two last demonstrate that methods can be used by a function that operate on procedures.

(define meth (<list> get occurences-of))

(meth L 1)           ;; --> 2

(apply meth L '(1))  ;; --> 2
(map meth `((,L 1))) ;; --> 2


 Stéphane Hillion - 1998