Chapter 8
Object-oriented programming in Scheme

Kurt NÝrmark
Department of Computer Science, Aalborg University, Denmark


Abstract
Previous lecture Next lecture
Index References Contents
In this side track lecture we will introduce the LAML system, which allows us to do web programming Scheme and in the functional programming paradigm


Closures revisited

Functions and closures
Slide Annotated slide Contents Index
References 
On this page we review some of the properties of function object - also known as closures. The contents of this pages is taken directly from an earlier pages in this material.

The concept function object: A function object represents a function at run time. A function object is created as the value of a lambda expressionA function object is a first class value at run time, in the same way as numbers, lists and other data are values. This is different from more traditional programming languages, where procedural and functional abstractions have another status than ordinary data.
The concept closure: A function object is also known as a closure.The name 'closure' is related to the interpretation of free names in the body expression of the function. Free names are used, but not defined in the body. In a function object (or closure) the free names are bound in the context of the lambda expression. This is a contrast to the case where the free names are bound in the context of the application of the function.

  • Characteristics of function objects:

    • First class objects

    • Does not necessarily have a name

    • A function object can be bound to a name in a definition

    • Functions as closures:

      • Capturing of free names in the context of the lambda expression

      • Static binding of free names

      • A closure is represented as a pair of function syntax and values of free names

    • A function object can be applied on actual parameters, passed as a parameter to a function, returned as the result from another function, and organized as a constituent of a data structure

Reference


Classes and objects in Scheme

Functions with private context
Slide Annotated slide Contents Index
References Textbook 

It is possible to define a private context around a function

Program: A template of a function with private context. The lambda expression appears in the context of the let name binding construct. When the definition is evaluated a name binding context is established around the lambda expression. The lambda expression is the only place in the program which have a possibility to reach the name bindings. Therefore the name bindings are local to the lambda expression. The CONTEXT is a list of name bindings, as such name bindings appear in a let construct.
(define function-with-private-context
 (let (CONTEXT)
   (lambda (PARAMETERS)
      BODY)))

Table. An example in which we abstract a (html (head (title..)) (body ...)) expression in a lambda expression, of which we define a private context. The context redefines the html and body functions to 'specialized' versions, with certain attributes. Notice the importance of the 'simultaneous name bindings' of let in the example (as explained in an earlier lecture). Also notice that we have discussed the modify-element higher-order function before.
Expression

Value

(define document
 (let
   ((html 
     (xml-modify-element html 
      'xmlns "http://www.w3.org/1999/xhtml"))
    (body 
     (xml-modify-element body 
      'bgcolor (rgb-color-encoding 255 0 0)))
      )
   (lambda (ttl bdy)
    (html
      (head (title ttl))
      (body bdy)))))
 
(document "A title" "A body")
<html xmlns = 
       "http://www.w3.org/1999/xhtml">
 <head>
  <title>A title</title>
 </head> 
 <body bgcolor = "#ff0000">
  A body
 </body>
</html>
 

References

Classes and objects
Slide Annotated slide Contents Index
References Textbook 

Due to (1) the first class status of functions, and due to (2) the use of static binding of free names, it is possible to interpret a closure as an object

With this interpretation, it is possible to regard certain function definitions as classes

Program: The send method which is used in the Point class. The function apply calls a function on a list of parameters. This should be seen in contrast to a normal call, in which the individual parameters are passed.
(define (send message obj . par)
  (let ((method (obj message)))
    (apply method par)))

Program: The definition of a 'class Point ' with methods getx , gety , add , and type-of . On this page we have also defined the syntactical convenience function send that sends a message to an object. In MzScheme, be sure that you define send before Point (such that send in the add method refers to our send , and not an already existing and unrelated definition of the name send ).
(define (point x y)
  (letrec ((getx    (lambda () x))
           (gety    (lambda () y))
           (add     (lambda (p) 
                      (point 
                       (+ x (send 'getx p))
                       (+ y (send 'gety p)))))
           (type-of (lambda () 'point))
          )
    (lambda (message)
      (cond ((eq? message 'getx) getx)
            ((eq? message 'gety) gety)
            ((eq? message 'add)  add)
            ((eq? message 'type-of) type-of)
            (else (error "Message not understood"))))))

Program: All necessary stuff to play with Point.
y:/Kurt/Files/courses/prog3/prog3-03/sources/notes/includes/point-all.scm

Exercise 8.2. Points and Rectangle

The purpose of this exercise is to strengthen your understanding of functions used as classes in Scheme.

First, play with the existing Point class defined on this page available from the on-line version of this material.

As an example, construct two points and add them together. Also, construct two lists of each four points, and add them together pair by pair.

Define a new method in the Point class called (move dx dy) , which displaces a point with dx units in the x direction and dy units in the y direction. We encourage you to make a functional solution in which move creates a new displaced point. After that you can make an imperative solution in which the state of the receiving point is changed.

Finally, define a new class, Rectangle , which aggregates two points to a representation of a rectangle. Define move and area methods in the new class.

As a practical remark to the 'class Point ' and the send primitive, be sure to define send before you define Point . (This is done to redefine an existing send procedure in MzScheme).

A general pattern of classes
Slide Annotated slide Contents Index
References Textbook 

The following shows a template of a function that serves as a class

Program: A general template of a simulated class. construction-parameters are typically transferred to the let construct, which we want to play the role as instance variables. Next comes explicitly defined methods, and last is the object handle called self . Notice that the value returned by the class is the value of self - the object handle.
(define (class-name construction-parameters)
 (let ((instance-var init-value)
        ...)
     
   (define (method parameter-list)
     method-body)

   ...
     
   (define (self message)
     (cond ((eqv? message selector) method)
	   ...
             
	   (else (error "Undefined message" message))))
     
   self))

Program: Accompanying functions for instantiation and message passing.
(define (new-instance class . parameters)
  (apply class parameters))

(define (send message object . args)
  (let ((method (object message)))
    (cond ((procedure? method) (apply method args))
          (else (error "Error in method lookup " method)))))

References

Example of the general class pattern
Slide Annotated slide Contents Index
References Textbook 

The Point class redefined to comply with the general class pattern

Program: The class Point implemented with use of the general class template. The Point class corresponds to the Point class defined on an earlier page. Notice that the bindings of x and y in the let construct is superfluous in the example. But due to the simultaneous name binding used in let constructs, they make sense. Admittedly, however, the let construct looks a little strange.
(define (point x y)
 (let ((x x) 
       (y y)
      )
     
   (define (getx) x)

   (define (gety) y)

   (define (add p) 
    (point 
     (+ x (send 'getx p))
     (+ y (send 'gety p))))

   (define (type-of) 'point)
     
   (define (self message)
     (cond ((eqv? message 'getx) getx)
           ((eqv? message 'gety) gety)
           ((eqv? message 'add)  add)
           ((eqv? message 'type-of) type-of)
	   (else (error "Undefined message" message))))
     
   self))

Program: All necessary stuff to play with Point.
y:/Kurt/Files/courses/prog3/prog3-03/sources/notes/includes/point-class-all.scm

Program: A sample construction and dialogue with point.
1> (define p (new-instance point 2 3))

2> (send 'getx p)
2

3> (define q (new-instance point 4 5))

4> (define p+q (send 'add p q))

5> (send 'getx p+q)
6

6> (send 'gety p+q)
8

A general pattern of classes with inheritance
Slide Annotated slide Contents Index
References Textbook 

The following shows a template of a function that serves as a subclass of another class

Program: A general template of a simulated class with inheritance.
(define (class-name parameters)
 (let ((super (new-part super-class-name some-parameters))
       (self 'nil))
   (let ((instance-variable init-value)
         ...)
       
     (define (method parameter-list)
       method-body)
     ...
       
     (define (dispatch message)
       (cond ((eqv? message 'selector) method)
             ...
             (else (method-lookup super message))))
       
     (set! self dispatch))
     
   self))

Program: A simulation of the root of a class hierarchy.
(define (object)
  (let ((super '())
        (self 'nil))

   (define (dispatch message)
       '())
 
   (set! self dispatch)
   self))

Program: Accompanying functions for instantiation, message passing, and method lookup.
(define (new-instance class . parameters)
  (apply class parameters))

(define (new-part class . parameters)
  (apply class parameters))

(define (method-lookup object selector)
 (cond ((procedure? object) (object selector))
       (else
         (error "Inappropriate object in method-lookup: "
                 object))))

(define (send message object . args)
 (let ((method (method-lookup object message)))
  (cond ((procedure? method) (apply method args))
        ((null? method)
         (error "Message not understood: " message))
        (else 
         (error "Inappropriate result of method lookup: "
                 method)))))

An example of classes with inheritance
Slide Annotated slide Contents Index
References Textbook 

We sketch one of the favorite toy specializations of Point - ColorPoint

Program: A specialization of Point which is called ColorPoint.
(define (color-point x y color)
 (let ((super (new-part point x y))
       (self 'nil))
   (let ((color color))
       
     (define (get-color)
       color)

     (define (type-of) 'color-point)
       
     (define (dispatch message)
       (cond ((eqv? message 'get-color) get-color)
             ((eqv? message 'type-of) type-of)
             (else (method-lookup super message))))
       
     (set! self dispatch))
     
   self))

Program: All necessary stuff to play with ColorPoint.
y:/Kurt/Files/courses/prog3/prog3-03/sources/notes/includes/colorpoint-class-all.scm

Program: A sample construction and sample dialogue with ColorPoint.
1> (define cp (new-instance color-point 5 6 'red))

2> (send 'get-color cp)
red

3> (send 'getx cp)
5

4> (send 'gety cp)
6

5> (define cp-1 (send 'add cp (new-instance color-point 1 2 'green))) 

6> (send 'getx cp-1)
6

7> (send 'gety cp-1)
8

8> (send 'get-color cp-1)
Undefined message get-color

9> (send 'type-of cp-1)
point

Exercise 8.3. Color Point Extension

On this page we have introduced the class ColorPoint, which inherits from Color .

In the sample dialogue with a couple of color points we have identified the problem that the sum of two color points is not a color point. Why is it so?

You are now supposed to make a few changes in the classes Point and ColorPoint. In order to make it realistic for you to play with the classes, your starting point is supposed to be a pre-existing file, with all the useful stuff (available from the on-line version of this material).

When you experiment with points and color-points, use M-x run-laml-interactively from Emacs.

  1. First take a look at the existing stuff, and make sure you understand it. Be aware that both of the classes Point and ColorPointuse virtual methods, as explained below.

  2. Add a method class-of to both Point and ColorPoint that returns the class of an instance. Underlying, the method class-of is supposed to return a function.

  3. Now repair the method add in Point, such that it always instantiate a class corresponding to the class of the receiver. In other words, if the receiver of add is a Point, instantiate a Point. If the receiver of add is a ColorPoint, instantiate a ColorPoint. You can probably use the method class-of from above. (If you run into a problem of a missing parameter in the instantiation of the 'sum point' - you are invited to take a look at my solution).

The interpretation of self
Slide Annotated slide Contents Index
References Textbook 

In order to obtain virtual methods of classes we need another interpretation of self

Figure. Two different interpretations of self . We see two linear class hierarchies. The class C inherits from B, which in turn inherits from A. And similarly, F inherits from E, which inherits from D. The one to the left - in the green class hierarchy - is the naive one we have obtained in our templates and examples until now. The one to the right - in the yellow class hierarchy, shows another interpretation of self . Following this interpretation, self at all levels refer to the most specialized object part.

A demo of virtual methods
Slide Annotated slide Contents Index
References Textbook 

On this page we will make two artificial classes with the purpose of demonstrating virtual methods

Program: A base class x . The method res sends the message get-state to itself. If an x object receives the message res , it will return the number 1.
(define (x)
 (let ((super (new-part object))
       (self 'nil))

   (let ((x-state 1) 
        )
     
     (define (get-state) x-state)

     (define (res)
       (send 'get-state self))

     (define (set-self! object-part)
         (set! self object-part)
         (send 'set-self! super object-part))
     
     (define (self message)
         (cond ((eqv? message 'get-state) get-state)
               ((eqv? message 'res) res)
               ((eqv? message 'set-self!) set-self!)
               (else (method-lookup super message))))
     
      self)))  ; end x

Program: A class y that inherits from x . The y class redefines the method get-state . The y class inherits the method res . If a y method receives the message res , it will be propagate to the x part of the object. Due to the use of virtual methods, self in the x part refers to the y part. Therefore the get-state message returns the y-state of the y part, namely 2.
(define (y)
 (let ((super (new-part x))
       (self 'nil))

   (let ((y-state 2) 
        )
     
     (define (get-state) y-state)

     (define (set-self! object-part)
         (set! self object-part)
         (send 'set-self! super object-part))
     
     (define (self message)
         (cond ((eqv? message 'get-state) get-state)
               ((eqv? message 'set-self!) set-self!)
               (else (method-lookup super message))))
     
      self))) ; end y

Program: A dialogue using class x and class y. Instances of the classes x and y are created and res messages are send to both of them.
1> (define a (new-instance x))

2> (define b (new-instance y))

3> (send 'res a)
1

4> (send 'res b)
2

Program: The functions new-instance and virtual-operations.
y:/Kurt/Files/courses/prog3/prog3-03/sources/notes/includes/class-x-y-all

Program: All the stuff necessary to play with x and y. The crucial observation is that the y object bound to the variable b returns the number 2 when we send it the res message.
y:/Kurt/Files/courses/prog3/prog3-03/sources/notes/includes/class-x-y-all

Exercise 8.4. Representing HTML with objects in Scheme

This is an open exercise - maybe the start of a minor project.

In the original mirror of HTML in Scheme, the HTML mirror functions, return strings. In the current version, the mirror functions return an internal syntax tree representation of the web documents. With this, it is realistic to validate a document against a grammar while it is constructed. In this exercise we will experiment with an object representation of a web document. We will use the class and object representation which we have introduced in this lecture.

Construct a general class html-element which implement the general properties of a HTML element object. These include:

  1. A method that generates a rendering of the element
  2. A method that returns the list of constituents
  3. An abstract method that performs context free validation of the element

In addition, construct one or more examples of specific subclasses of html-element , such as html , head , or body. These subclasses should have methods to access particular, required constituents of an element instance, such as the head and the body of a HTML element, and title of a head element. Also, the concrete validation predicate must be redefined for each specific element.


Collected references
Contents Index
Foldoc: closure
modify-element
let - simultaneous name binding
Simulation of Object-oriented Concepts and Mechanisms in Scheme
Simulation of object-oriented mechanisms in Scheme - A technical report

 

Chapter 8: Object-oriented programming in Scheme
Course home     Author home     About producing this web     Previous lecture (top)     Next lecture (top)     Previous lecture (bund)     Next lecture (bund)     
Generated: January 3, 2014, 09:49:30