# Course 287 - Lecture 11 State, the Imperative Paradigm and Object Orientation

State in Scheme
Using let statements to create extra slots
An extension of set! in UMASS Scheme uses updaters

#### Abelson & Sussman

Chapter 3 in the textbook covers the material discussed in this lecture and subsequent lectures. The initial sections up to 3.3.3 are particularly relevant.

## State in Scheme

Many computations in real world applications of computing require that we need a concept of state.

• Travel reservations
• Banking
• Status of students in University records.

### set! provides assignment

Scheme provides a special form (set! var expr) to support this. It is equivalent to the assignment statement var := expr in Pascal, or var = expr in the C language. The interpretation of set! is that the expression expr is evaluated and the variable var is rebound to have the resulting value.

Note that when it occurs at the top level the (define var expr) special form creates a new variable var if it does not already exist, and then does in effect (set! var expr). The following example shows how assignment can be used to record the amount of money held in a single bank account - this is of course equivalent to a very elementary Pascal or C program.

``````
(define balance 100)

(define withdraw!
(lambda (amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
(list 'balance balance)
)
"Insufficient funds"
)
)
)
``````
Note that there is a convention that procedures which act imperatively have names ending in a shriek, as in withdraw!.
``````
(example '(withdraw! 34) '(balance 66))

(example '(withdraw! 60) '(balance 6))

(example '(withdraw! 8)  "Insufficient funds")

``````
When combined with the concept of higher order functions we get some interesting behaviour. The following example shows how we can make the balance be a variable associated with an arbitrary number of individual accounts, essentially by wrapping the withdraw! function above in an outer function.
``````
(define (make_account balance)
(lambda (amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
(list 'balance balance)
)
"Insufficient funds"
)
)
)
``````
``````
(define jane (make_account 200))
(define andrew (make_account 100))
``````
``````
(example
'(jane 40)
'(balance 160))

(example
'(andrew 45)
'(balance 55))

(example
'(andrew 65)
"Insufficient funds")

(example
'(jane 5)
'(balance 155))

``````

Note that in introducing set! we have destroyed our ability to explain Scheme purely in terms of substitution. Consider evaluating (make_account 100). Substituting 100 for balance in the body:

```    (lambda (amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
(list 'balance balance)
)
"Insufficient funds"
)
)
```
we obtain
```    (lambda (amount)
(if (>= 100 amount)
(begin (set! 100 (- 100 amount))
(list 'balance 100)
)
"Insufficient funds"
)
)
```
Which has a nonsensical assignment to a constant. When we construct a model evaluators for Scheme in subsequent lectures, we shall see how the conceptually simplest evaluator fails to give an account of set!.

## Using let statements to create extra slots

Suppose we want to make a record of the number of transactions made into a given account. We can do something like this.
``````
(define (make_account balance)
(let ((n_trans 0))
(lambda (amount)
(if (>= balance amount)
(begin
(set! balance (- balance amount))
(set! n_trans (+ n_trans 1))
(list 'transaction n_trans 'balance balance)
)
"Insufficient funds"
) ;end if
)     ;end lambda
)         ;end let
)             ;end define

``````
``````
(define jane (make_account 200))
(define andrew (make_account 100))

(example
'(jane 40)
'(transaction 1 balance 160))

(example
'(jane 20)
'(transaction 2 balance 140))

``````

## An extension of set! in UMASS Scheme uses updaters

UMASS Scheme supports an extension of the set! construction.
```    (set! expr1  expr2)
```
is interpreted as follows. First, let us note that procedures in UMASS Scheme have an updater attribute, which is normally itself a procedure.
• If expr1 is a variable then set! behaves in the usual way.
• However if expr1 is an expression (expr11 expr12 expr13...expr1n) then expr11, expr12, expr13...expr1n are evaluated, as is expr2.
• If expr11 does not evaluate to a procedure object, then there is an error.
• If it is a procedure-object p say, then the result of evaluating the set! expression is the same as the result of evaluating
`((updater p)  expr2 expr12 expr13...expr1n)`
This may, of course, result in an error if the updater is not a procedure. For example
```(set! (+ 2 3) 34)
```
will earn you a scolding from Madeleine Misconception.

The above explanation sounds complicated. However the use of this facility is usually quite simple, since the updaters of built-in functions are designed to do the intuitive thing. For example you can use set! to change the first element of a list.

```(define a '(fred joe))

(set! (car a) 'anne)

(example '(car a)  'anne)
```
Also, the selector-functions produced by record-class are designed to be used in this way with set!

After and including Version 3.5 of UMASS Scheme, there is a function updater which returns the updater of its argument.

### The ->string function

The function-call (->string expr) in UMASS Scheme converts the value of the expression expr to a string whose characters are the same as the sequence of characters output by
(display expr)
```(example  (->string (+ 3 4))  "7")
```

## 1 What is Object Orientation?

It is fairly easy to say what the functional and logic paradigms are about:

• The functional paradigm takes as its theoretical basis the lambda calculus.
• The logic paradigm takes as its theoretical basis the predicate calculus.

It is somewhat harder to characterise the imperative paradigm.

• The imperative paradigm supports explicit local state changes and so reflects more closely the actual architecture of computers. (while the pure functional paradigm for example provides only state change to the global environment - you may define another function for example).

The object oriented paradigm is about (a) creating "objects" in which behaviour is associated with data and (b) ways in which these objects can be placed in a hierarchy in which one kind of object can inherit the behaviour of others and (c) ways in which the structure of objects can be encapsulated so as to allow only legitimate enquiries to be made about them.

Now (a) and (c) are both properties of closures - a closure is an association of behaviour (i.e. some code) with data, and the data can only be accessed only by passing appropriate arguments to the closure. So there is something of an overlap of capabilities between the function paradigm and the object-oriented paradigm.

We often speak of the piece of code that implements a particular behaviour for a class of objects as a method. In general the essential aspect of object orientation is that a named action applied to an object is mapped on to a piece of code for effecting that action by means of a flexible mapping which takes into account both the name of the action and the class of object to which it is applied.

## 2 The sub-paradigms in object-orientation 

There are two sub-paradigms within object orientation:

### 2.1 The message-passing sub-paradigm

In this sub-paradigm an object is "sent" a "message" to cause it to exhibit behaviour. For example, if we were simulating a university, we might have person objects, each one of which could be told to print himself or herself. This could be accomplished, with a Scheme implementation of this sub-paradigm, by:

```      (send  person 'print)
```

which might cause the output:

```     name: Frederika Forsythe
age:  42
sex:  female
```

Likewise

```     (send person 'age)
```

might return the result 42.

Sometimes arguments are embodied in the message, for example

```       (send person 'location 234 456)
```

might be used to reposition a person in a simulation that went into topographic detail.

The most significant development of this paradigm was associated with the Smalltalk language.

Within this paradigm, a general concept of inheritance corresponds to the possibility that one class of objects may share some of the attributes of another class. For example, in our university model we would have students who are a kind of person and professors who are a kind of person. Students will be able to handle all the messages that a person can handle - they have ages, sexes, addresses etc.. However they also have attributes peculiar to students, such as the courses that they take. Moreover they may respond differently to standard messages.

```
(send student 'print)

name: Jeremiah Jolt
age:  23
sex:  male
course: CMPSCI 287, STATS 101
```

and

```     (send student 'courses)  ==> '( (CMPSCI 287) (STATS 101))
```

The "send a message" approach has some virtues. It is a quite natural way of talking about a distributed system in which the objects are not all resident on a single computer so that information has to be transferred via some kind of communication link, for example a local area network.

It also has some snags, not least among which is the fact that the nice higher-order functions we have written in this course are not so readily applicable to this paradigm. For example if we wanted to convert a list of students into a list of lists of the courses they were taking we could not use map in quite such a simple way. In the functional paradigm, if courses was a function mapping from students to their courses, we would write

```      (map courses students)
```

whereas in the message-sending sub-paradigm we have to write: (map (lambda (s) (send s 'courses)) students)

Moreover the fact that a message has to be addressed to one object makes it tricky to implement certain functions which naturally involve two objects, such as comparing them for equality.

One common term for this limitation is that this approach embodies single dispatch, that is methods are selected on the basis of a single object (and are usually associated fairly directly with that object).

One can regard the C++ language as supporting a single-dispatch approach to method invocation.

### 2.2 The distributed-function-definition sub-paradigm

The Common Lisp Object System (CLOS) and the objectclass library of the POP-11 language support a different sub-paradigm, one in which object orientation is effected by extending the definition of functions in an incremental way. In Scheme syntax, one would say:

```      (print person)
```

and have the same information printed out

```     name: Frederika Forsythe
age:  42
sex:  female
```

However, instead of the print function being defined in one place

```(define (print person)
(print-basic-info person)
(cond ((student? person) (print-student-info person))
((professor? person) (print-prof-info person))
)
)
```

the definition of how to print a person is distributed among various method definitions, using a new special form. 3 An example using the POP-11 objectclass library.

By way of a change we will consider the objectclass library for POP-11, written by Steven Knight of Hewlett Packard Laboratories, Bristol. POP-11 is derived from POP-2 [Burstall & Popplestone 1968], and is in essence a form of LISP with ALGOL-60 derived syntax. For example the factorial function in POP-11 is defined as:

```    define fact(n);
if n=0 then 1 else n*fact(n-1)
endif
enddefine;
```

To enter POP-11 from Scheme, execute the function call (pop11) in your base window. To get back, type "Scheme". There is no literate version of POP-11, so you'd have to comment out the English (with the /*...*/ comment brackets familiar to C users.

In POP-11, to print an expression expr you do

```    expr =>
```

For example

```    fact(5) =>
```

will print out

```** 120
```

Finally, to declare a new global variable, and give it a value, one uses vars command, exemplified below:

```    vars x = fact(120);
```

creates (if required) a new variable x  and makes it have fact(120)  as its value.

### 3.1 Defining person records

To load the objectclass library we need to execute the POP-11 command: lib objectclass;

This will take some tens of seconds, during which the message: ;;; Objectclass, version 5.02 ;;; Loading source files. ;;; Done.

is printed out. We are now ready to define our basic person class of objects. This is done with the following syntax:

```define :objectclass person
name     = 'John Doe';
age :int = 25;              ;;; The type-constraint is optional.
sex      = 'male';
enddefine;
```

This has the effect that each member of the person class is a record with three fields for name, age and sex. These fields are accessible with three functions name, age and sex which are created (or extended) by the objectclass declaration.

The declaration also creates two functions (called newperson and consperson) for creating person objects and one function (destperson) for taking them apart.

• The function call: newperson() creates object with the default fields specified in the class-definition above.
• The function call: consperson('Jane Roe', 34, 'female') creates a person record with name 'Jane Roe', age 34, and sex 'female'.

We don't need to consider the effect of the destperson function.

Thus, we can create a new person object, and bind the variable p1 to have it as its value by:

```    vars p1 = newperson();
```

and print out the new person, using a default print-method that is created when the person objectclass is created:

```    p1=>
```
```**
```

### Object orientation in an Imperative Framework

Object oriented languages designed from an imperative perspective usually distinguish between fields which an object may have, and methods which may access these fields. Fields are very like fields in a conventional data-structure (records in Pascal, or structures in C). POP-11's lib objectclass creates records which, internally have these fields, but which are only accessible by methods created specifically to access them. The terms "constructor" and "destructor" are used differently in O-O languages with an imperative background. A constructor is a user-definable method-like piece of code which typically specifies how the fields of an object newly allocated by the memory allocator are to be filled in. In C++, a destructor is a method-like piece of code specifying how to de-allocate an object. The Java language, in which objects are normally garbage-collected, does not have destructors, although it provides a user-definable finalize method for objects containing entities (files, windows) that may need specific action to delete them.

### 3.2 Defining a method to print a person object.

If we don't like the way the default print function works, we can define a function print for a person by defining the method:

```define :method print(p:person);
printf('name: %p \n',  cons(name(p),[]));
printf('age: %p \n',   cons(age(p),[]));
printf('sex: %p \n',   cons(sex(p),[]));
enddefine;
```

Here printf is a system function which loosely follows the convention of the printf function of the C language, that is to say, the first argument specifies a string with "slots" %p which will be filled in by values taken from the list which is the second argument. The empty list is denoted by [] in POP-11, and cons is a POP-11 function corresponding to the Scheme cons function.

Now if we say:

```    print(p1);
```

we obtain the output:

```    name: John Doe
age: 25
sex: male
```

We can create another person:

```    vars p2 = consperson('Frederika Forsythe',42,'female' );
```

so that evaluating:

```    print(p2)
```
produces the output:
```    name: Frederika Forsythe
age: 42
sex: female
```

### 3.3 Creating student as a sub-class of person

We can now create students as a kind of person:
```    define :objectclass student isa person;
classes = ['CMPSCI 287' 'MATH 183'];
enddefine;
```
Here the force of the isa construct is to say that the new student class of objects ________inherits all the attributes of a person (name, age and sex) and by default inherits the _______methods that apply to a person. To be precise, the records that implement the student object have fields for name, age, sex, with methods of those same names. However, a student object has a new attribute, namely the classes attribute. vars s1 = newstudent(); If we print s1 using the built-in generic printing function of POP-11, we see that students have inherited the attributes of people, but have classes as well: s1=> ** however the print function which we wrote, with a method defined for the person class, treats a student as a person, printing out just name, age and sex: print(s1); produces the output name: John Doe age: 25 sex: male We can give the student object-class its own printing method:
```    define:method print(s:student);
printf('classes: %p \n',   cons(classes(s),[]));
enddefine;
```
However if we call this, we simply get the information about classes:
```    print(s1);
```
gives:
```    classes: [CMPSCI 287 MATH 183]
```
We could of course print out the people-attributes of a student, by copying our earlier code for printing persons, but more conveniently there is a special form defined in lib objectclass, namely call_next_method, which will, in this case, call the method for the person objectclass.
```define:method print(s:student);
call_next_method(s);
printf('classes: %p \n',   cons(classes(s),[]));
enddefine;
```
Now we find that:
```    print(s1);
```
will produce:
```    name: John Doe
age: 25
sex: male
classes: [CMPSCI 287 MATH 183]
```
How does call_next_method work? Well, the isa construct defines an ______object _________hierarchy in which the student class comes immediately below the person class. The expression call_next_method(s), knowing that s belongs to the student class of objects, arranges for the method appropriate to the next higher class in the hierarchy, that is the person class, to be called.

### 3.4 Multiple dispatch in lib objectclass

This approach supports multiple dispatch, that is to say one can qualify some or all arguments of a method with class membership constraints. For example, one might define one person as being senior to another in terms of age:

```    define :method senior(p1:person, p2:person);
age(p1) > age(p2)
enddefine;
```
Whereas one might define one student as being senior to another in terms of the number of classes taken:
```    define :method senior(s1:student, s2:student);
length(classes(s1)) > length(classes(s2))
enddefine;
```
What happens if we try to compare a student with a non-student. The system searches the class-hierarchy to find a method that applies to both. In this case the definition of senior for two people is used. Where a class-hierarchy has some complexity it is possible that more than one method may exist which is applicable to the arguments of a multiply-dispatched method call. What is to happen in this case? In fact lib objectclass uses a simple lexicographical rule to make the choice. The Common Lisp Object System does this by default, although this default is user-modifiable. The Java language, which does this kind of search at compile-time, insists on finding a unique _________maximally ________specific method-descriptor [Gosling, Joy & Steele 1996]. __________References Burstall, R.M. and Popplestone, R.J.,  The POP-2 Reference Manual, Machine Intelligence 2, pp. 205-46, eds Dale,E. and Michie,D. Oliver and Boyd, Edinburgh, Scotland. Gosling,J. Joy,B. and Steele,G. The Java Language Specification. Addison Wesley.