CSE130 LECTURE NOTES

May 13, 2002
 
 

ADMINISTRATION

Reminder: The midterm will be next Monday in class (Center Hall room 119).  The midterm is intended mainly as practice for the final exam, which will be on Monday June 10, from 7pm to 10pm, also in Center 119.  Today's handout is a sample exam including solutions.

The policy for what you can use during the exams is as follows:  You may bring and use your own personal hand-written notes, and a printed copy
of the published lecture notes.  You may not use any books or any other materials.
 
 

INHERITANCE

From a programming language (as opposed to programming methodology) point of view, the major innovation in OOP is inheritance.  Here is an example of what is called a derived class definition:
class tax-history parent financial-history =
begin
    state deductions;
    method init = deductions := [];
    method deductible-spend (amount) =
        deductions := append(amount,deductions);
        send self spend(amount);
end;
Every object of type tax-history has three financial-history state variables, plus one new state variable. It can respond to all financial-history messages, and some additional messages.
 
 

DYNAMIC BINDING

With inheritance there is a problem concerning how methods are bound to method-names.

One method of an object can call another of the same object if necessary. The name self refers to the current object, which is the implicit first argument of each method.

Calls to a self-method should refer to the method with the given name in the child class. This allows child class methods to override parent methods.

For example, sending the message id to an object of class D with the following class definitions should give I'm a type D object:

class C =
begin
    method whoami = return "I'm a type C object";
    method id = print (send self whoami)
end;

class D =
begin
    method whoami = return "I'm a type D object";
end;

Under standard static scoping, the name whoami in the body of the method C.id would refer to the method C.whoami. This is not what we want.

Method names should follow dynamic binding: the method corresponding to a name should be found in the run-time environment, not in the compile-time environment.
 
 

OOP KEYWORDS

(1) Object identity. Even if two objects have the same internal value, they are still different objects.  Similarly, two variables are different even if temporarily they have the same value, because they have different locations, and hence in the future they can be updated differently.

Object identity is connected to an "object-centric" view of programming: every operation is about some primary object.  Syntactically, every method has an unwritten (implicit) first argument, which is the object itself.

(2) Encapsulation. The state of an object is private to the object: the only way the state can be changed or observed is by calling one of the object's methods. This is what we called "implementation-hiding" before.

(3) Overloading. Two objects of different classes can have a method with the same name. If these methods perform conceptually similar operations, the caller of the method does not need to know the exact class of the called object.  Overloading is particularly important with inheritance.
 
 

OWN VARIABLES REVISITED

Another point of view on objects is that an object is a single procedure with some variables that are global and private, i.e. they keep their values between calls to the procedure but they can only be updated inside the procedure.  The methods of the object are alternative instructions that the object can execute.

According to this view, the object itself is really a dispatcher: it waits for a message and then selects one of its methods for execution based on which message was received.  A class is a function that can generate new objects.  For example:

type messages = (next, restart);

function newgenerator (initial:real) =
begin
    var seed: real := initial;
    return
        function (m: messages) =
        begin
            case m of
                next: seed := transform(seed);
                restart: seed := initial;
            end;
            return seed;
        end;
end;

function myrandom = newgenerator(1.2345);
function hisrandom = newgenerator(0.1428);

Here newgenerator is a higher-order function that returns another function, which is anonymous. Each returned function is a pseudo-random number generator (PRNG) that can respond to two alternative messages.

The updated PRNG seed is kept in the variable seed which is local to newgenerator so seed is fresh each time that newgenerator is called.  However seed is global to the anonymous function so each version of seed keeps its value between calls to the corresponding individual PRNG.
 
 



Copyright (c) by Charles Elkan, 2002.