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.
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.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;
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:
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.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;
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.
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.
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:
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.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);
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.