0% found this document useful (0 votes)
7 views14 pages

Lecture 6 - Object Orientation

Uploaded by

DA BEST
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views14 pages

Lecture 6 - Object Orientation

Uploaded by

DA BEST
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 14

Further Programming

Paradigms
Lecture 6: Abstract Data Types and Object Orientation

Prof. Paul Krause, University of Surrey


This lecture’s objectives

• Continue the theme of data types as controlled documentation of a


program

• Use Abstract Data Types to introduce the notions of encapsulation


and interface

• Then talk about the additional requirements for defining your own
types, which motivates the move to OO
Structuring Data

• The following material is taken from Chapters 9 and 10 of


Programming Languages: Principles and Paradigms

• The underlying physical machine (at least w.r.t. electronic computers)


manipulates material of only one type: bit strings

• The type system associated with a programming language wraps


each data value in an encapsulation which provides operations that
can be used to manipulate it

• We talked about predefined types, and you will also have seen in
other lectures mechanisms for defining new ones, for example: arrays
(homogenous aggregations); and, records (heterogenous
aggregations)

• But these are rather restrictive. Are there more flexible ways of
defining new types?
We could try something like this …
type Int_Stack = struct{
int P[100]; // the stack proper
int top; // first readable element
}
Int_Stack create_stack(){
Int_Stack s = new Int_Stack();
s.top = 0;
return s;
}
Int_Stack push(Int_Stack s, int k){
if (s.top == 100) error;
s.P[s.top] = k;
s.top = s.top + 1;
return s;
}
int top(Int_Stack s){
return s.P[s.top];
}
Int_Stack pop(Int_Stack s){
if (s.top == 0) error;
s.top = s.top - 1;
return s;
} …
BUT

There is nothing to stop us interacting directly with the stack’s


representation:
int second_from_top()(Int_Stack c){
return c.P[s.top - 1];
}
Requirements for an Abstract Data Type
(ADT)

An ADT is characterised by the following [Gabbrielli and Martini, 2010]


1. A name for the type.
2. An implementation (or representation) for the type.
3. A set of names denoting operations for manipulating the values of
the type, together with their types.
4. For every operation, an implementation that uses the representation
provided in point 2.
5. A security capsule which separates the name of the type and those
of the operations from their implementations.
ADT: Name and implementation for
Int_Stack

abstype Int_Stack{
type Int_Stack = struct{
int P[100];
int n;
int top;
}

}
The Signature, or Interface, of our ADT

abstype Int_Stack{
type Int_Stack = struct{
int P[100];
int n;
int top;
}
signature
Int_Stack create_stack();
Int_Stack push(Int_Stack s, int k);
int top(Int_Stack s);
Int_Stack pop(Int_Stack s);
bool empty(Int_Stack s);

}
An implementation of the interface

abstype Int_Stack{

operations
Int_Stack create_stack(){
Int_Stack s = new Int_Stack();
s.n = 0;
s.top = 0;
return s;
}
Int_Stack push(Int_Stack s, int k){
if (s.n == 100) error;
s.n = s.n + 1;
s.P[s.top] = k;
s.top = s.top + 1;
return s;
} …
Representation independence

We could also implement Int_Stack as, for example, a linked list. Both
implementations would respect the same specification:
• create_stack creates an empty stack.
• push inserts an element into the stack.
• top returns the element at the top of the stack without modifying the
stack itself. The stack must not be empty.
• pop removes the top elements from the stack. The stack must not be
empty.
• empty is true if and only if the stack is empty.

In this case we expect to have the representation independence


property:
Two correct implementations of a single specification of an ADT are
observationally indistinguishable by the clients of these types.
[Gabbrielli and Martini, 2010]
Limitations of ADTs

• We seem to be heading towards the OO that you all know and love.
But we are not there yet. Consider this example:
abstype Counter{
type Counter = int;
signature
void reset(Counter x);
int get(Counter x);
void inc(Counter x);
operations
void reset(Counter x){
x = 0;
}
int get(Counter c){
return x;
}

}
Enhance requirements for defining our own
types

We need constructs that:


• Permit the encapsulation and hiding of information.
• Are equipped with a mechanism which, under certain conditions,
supports
the inheritance of the implementation of certain operations from
other, analogous constructs.
• Are framed in a notion of compatibility defined in terms of the
operations
admissible for a certain construct.
• Allow the dynamic selection of operations as a function of the
“effective
type” of the arguments to which they are applied.
Creating a NewCounter from Counter in OO

class Counter{
private int x;
public void reset(){
x = 0;
}
public int get(){
return x;
}
public void inc(){
x = x+1;
}
}
Creating a NewCounter from Counter in OO

class Counter{ class NewCounter


private int x; extendsCounter{
public void reset(){ private int num_reset = 0;
x = 0; public void reset(){
} x = 0;
public int get(){ num_reset += 1;
return x; }
} public int num_resets(){
public void inc(){ return num_reset;
x = x+1; }
} }
}

You might also like