Title: Object Oriented Programming
1Object Oriented Programming
- Programming Languages 1
- Robert Dewar
- Fall 2003
2Object Oriented Design
- This term refers to a design principle (not to
any particular prog lang features) - In OOD, the problem is modeled as interaction
between objects - The computation focuses on the objects rather
than on procedural computations
3What is an Object?
- An object is a structure that may (and usually
does, hence the name) have internal state. - It is associated with methods that are prepared
to accept messages from other objects. - The computation is modeled in terms of message
passing between objects.
4Simula-67
- This was the first object oriented language. As
you can tell from the name it is old (40 years
old!) - So this is not a new idea!
- In Simula-67, each object is a separate thread of
control - From a PL point of view, each object is a task or
thread, and message passing involves
synchronization between threads.
5More on Simula-67
- The idea behind the language is that in real
life, systems consist of independent objects
(machines, people, reactive systems etc) - These objects then interact with one another.
- The language allows modeling of these objects to
simulate the real life system
6More on OOD
- OOD is possible in any language
- Objects can be modeled using available datatypes
- Along with specific sets of procedures or
functions that correspond to the methods - The association of methods with objects in a
non-OO language is one of convention and
organization
7OOD Methodology
- Object Oriented Design is all about finding the
objects in your problem space - Then representing them as objects in your program
- Then modeling the system by interactions between
these objects using message passing. - Various formal methodologies e.g. HOOD allow OOD
to be independent of actual program.
8Pure Object Oriented Design
- Absolutely everything is an object
- There is no data other than objects
- Even an integer is an object
- hello integer object, I have a message to send
you that contains an integer value. The value is
3. Could you please add this to yourself and
report back. - No problem, I did as you asked, and the result
is 5
9So What is Relation of OOD with OOP (Object
Oriented Programming)?
- Less than you think!
- Lets go back further here
- We will start with a structure (or record)
- This can be used to hold arbitrary heterogenous
data. - We might think of this as an object, but thats
not necessarily helpful if we dont adopt an OOP
view of the world.
10Abstract Datatypes
- If we take the record, and associate a number of
procedures and functions with the record type - And then we declare that access to variables of
this type (we hesitate to use the word objects
which is overloaded here - Object, an object in the OOD sense
- Object, a variable/constant of some type
11More on ADTs
- The only access allowed is via the procedures and
functions. - We access or change data within the ADT by
calling one of these procedures or functions
passing a variable of the appropriate type as an
argument. - So far this does not have anything directly to do
with OOD
12ADT Support in Languages
- We can do ADTs in any language by adopting
conventions - But pleasant languages have specific support for
this notion - A way of associating the functions and procedures
with a particular type - A way of hiding away the data so that it cannot
be accessed
13ADTs in Ada and C
- In Ada
- The package is the mechanism for associating
procedures and functions with a type. More
accurately, association in a declarative region. - Access is restricted by use of private types
- In C
- The class is the mechanism for associating
procedures and functions with a type. - Private members provide privacy
14ADTs and Code Reuse
- Reusing code is a good thing
- Suppose we have programmed some useful ADT
- Now we want to use that ADT directly, great, we
can use it as is, unchanged ? - But suppose we want to use a slightly modified
version, then we have to mess with the sources,
not good ?
15An Example of Reuse
- Binary tree ADT
- Handles adding new nodes
- Allocating and deleting nodes
- Traversing the tree
- But what I need is an AVL tree
- Which is a binary tree with
- An extra flag on each node for balance
- Balancing routines
16The Goal ReuseWithout Source Modification
- Achieved using four separate but related concepts
- Type extension adding new fields to an existing
data structure (type) - Inheritance when new fields are added, old
operations still work on modified type - Overriding allowing redefinition of operation
- Dynamic dispatching Same operation does
different thing on different modified versions,
and we choose right operation at run-time.
17Type Extension
- We have a record type
- type T is record . end record
- And now we want to add a field to this record
- We can either do this manually
- Or we can have the Prog Language help
18Manual Type Extension
- type Nodetype Node_Ptr is access Nodetype
Node is record Lson, Rson Node_Ptr Value
Integerend record - type AVL_Node is record Parent Node
Balance Balance_Typeend record - Now all those operating on AVL_Node can access
the parent field and apply operations of the
parent type.
19Type Extension in the PL
- Example is Ada (but langs are similar!)
- type Node is tagged record Lson, Rson
Node_Ptrend record - Here tagged indicates that the type can be
extended (we will see why it is called tagged in
a moment). And to extend it - type AVL_Node is new Node with record Balance
Balance_Typeend record
20Type Extension in the PL
- Now objects of type AVL_Node can be treated as
also being of type Node - The trick is to model the parent structure of the
previous slide so that the parent is first in the
record.
21Inheritance
- We want basic operations defined on the parent
type to be available for the child type. - Again two ways of doing things
- Manual (goes along with manual type extension)
- Have the PL help (goes along with PL helping with
extension)
22Manual Inheritance
- We just reference the parent field
- Suppose Left is defined on Node
- function Left (N Node) return Node_Ptr
- Now if we have an AVL_Node
- function to_Anode_Ptr is new Unchecked
Conversion (Node_Ptr, Anode_Ptr)Anode
AVL_NodeX To_Anode_Ptr (Left
(Anode.Parent))
23Inheritance built in to Language
- We extend the type as before
- type AVL_Node is new Node with record Balance
Balance_Typeend record - Now the operations apply directly, so we
automatically have a Left defined on AVL_Node - Anode AVL_NodeX Left (Anode)
- Automatically applies Left to the parent. So an
AVL_Node is a Node (just a rather special one)
24Overriding
- This allows us to inherit some operations
- But in other cases we want special versions
- For example
- Procedure Dump_Node (N Node)
- It makes no sense use the same code to try to
dump an AVL_Node since it would only dump the old
fields, and not the Balance
25Manual Overriding
- Just declare a new procedure
- function Dump_AVL_Node (N AVL_Node) isbegin
Dump_Node (N.Parent) Print (N.Balance) end
Dump_AVL_Node - And by convention always use Dump_AVL_Node when
dealing with AVL_Nodes.
26Overriding Built Into Language
- When we extend type, we get a Dump_Node by
automatic inheritance - But we dont want that so we override
- procedure Dump_Node (N AVL_Node) is
Dump_Node (Node (N)) Print (N.Balance)end
Dump_Node - Now any use of Dump_Node on AVL_Node will use the
overriding subprogram.
27When to Override
- When we want a different behavior (the Dump_Node
procedure of the previous slide is an example of
this). - When the original operation cannot be used.
Notably in the function case - function Empty_Node return Node
- This code returns a Node, so it cannot return an
AVL_Node - Overriding mandatory in this case
28Dynamic Dispatching
- When we extend type T1 to make type T2, the
general term we use is subtyping, so that we say
T2 is a subtype of T1. - This is EXACTLY wrong terminology in Ada, here we
say T2 is a derived type of T1, and subtypes are
something else - In either case, the deriving operation creates a
family of related types
29Related Types
- The types are related both
- Conceptually. Remember that we said that an
AVL_Node is a node, so we are talking about the
family of various kinds of nodes. - Physically, the parent is at the start, so all
objects in the family start with the same layout
(of the original ancestor). - We get a family of types rooted at a particular
type (a type and its descendents) which share
this relation.
30Handling Families of Objects
- Suppose we have a bunch of objects of various
different types within the same family, e.g.
Node, AVL_Node, Red_Black_Node,
Node_With_Extra_Field, AVL_Node_With_Count etc. - Supose we deal with pointers
- Someone receiving a pointer could treat it as
always being a Node
31Applying Operations to a Family
- Given P, a pointer to a particular element of the
node family, we can treat it as a Node. - And we can apply e.g. Lson, Rson and it will work
with any possible element of the family, since
e.g. an AVL_Node starts with a node. - We are nearly there
32Dispatching Manually
- Given AP, a pointer to an AVL_Node, do a manual
forced conversion - function To_P is new Unchecked_Conversion
- (AVL_Node_Ptr, Node_Ptr)X Left (To_P
(AP).Parent) - This works because the pointer to the AVL_Node
also points to a Node structure.
33Dispatching Automatically
- (but not quite dynamically yet ?)
- We have the type NodeClass which can reference
any element of the family. - Now we can apply Left directly
- type NC_Ptr is access NodeClassNCP
NC_PtrX Left (NCP.all) - The function Left on NodeClass is defined
automatically, and works on any element of Node.
34Finally Getting to Dynamic Dispatching
- This is not right for Dump_Node
- We really want to apply Dump_Node to an element
of the class, and automatically have the right
Version of Dump_Node applied. - This is called dynamic dispatching, since we have
to dynamically determine which version of Nodes
we have and choose the right Dump_Node.
35Automatic Dynamic Dispatch
- We have the type NodeClass which can reference
any element of the family. - Now we can apply Dump_Node directly
- type NC_Ptr is access NodeClassNCP
NC_PtrDump_Node (NCP.all) - The function Dump_Node on_Node NodeClass is
defined automatically, and works on any element
of Node - AND AUTOMATICALLY GETS THE RIGHT DUMP_NODE!
36How Did That Work???
- The mechanism here is tricky (and will finally
explain the tagged in the Ada definition of an
extensible type). - The tag is an actual field in the record.
- Every node object has a tag
- The tag is a pointer to a table
- The table contains a pointer with one entry per
associated subprogram
37More on the Dispatch Table (VTable)
- The table (Vtable) has one entry for each
associated subprogram. - (Vtable is the normal terminology in C)
- The table entry is a pointer to the right
version. - Calling a routine consists of looking up the
entry in the table and then indirectly calling
that routine.
38Building the Dispatch Table
- All objects of a given type point to the same
dispatch table. - Dispatch table is build when type is declared.
- When type is extended, extended type gets
dispatch table of parent, extended by any new
associated subprograms - Entries in this table are overwritten if
corresponding operations are overridden
39Can we Do Dynamic Dispatching Manually?
- Sure, just make the Vtable and explicit type
- Make the pointer to it explicit
- Replace a call with the steps to extract the
right entry and make an indirect call - Thats a pain!
- Which is why we like OOP features built into the
language
40Wait A Moment, Did you say OOP?
- Yes, these four language features are
collectively called Object Oriented Programming
Features - But we didnt mention objects when discussing
them - Thats right, they are generally applicable to a
wide range of ADTs - So why are they called OOP features?
41Object Oriented Programming
- One of the things that these OOP features are
useful for is in reusing definitions of objects - The state of an object is represented by an
abstract data type. - The notion of a set of associated subprograms
maps naturally to a set of methods for the object.
42Doing OOD using OOP Features ?
- Each associated subprogram is a method of the
object - So it must have as a parameter the object to
which it refers. - For example, in Ada
- type Obj is procedure Update (This Obj Val
Integer)Myobj ObjUpdate (Myobj, 23)
43If we Really Like OOD
- We can go a bit further
- Since all methods will have a This parameter,
lets make it implicit (no need to keep declaring
it in each function). - But we still need to say which object
- Since the method belongs to an object, think of
the method as part of the object.
44The C Style
- A class encapsulates an object, its data fields,
and the associated methods. - The methods implicitly get a this parameter and
can just refer to elements of the current object - To make the call, we use prefix notation
- Obj.Update (3)
45Going Further
- If we really want to go further, we should insist
that the ONLY functions and procedures are
methods for objects - Thats where Java goes (C still allowed
unattached functions). - Of course you can still have a Nothing object
which has real procedures, but the emphasis
becomes oriented to OOD.
46Multiple Inheritance
- So far we have been using OOP features for single
inheritance - Model is clean and nice
- But what if you have a class persistent that
provides persistence and a class tree that
provides trees, and you want a persistent tree. - No problem, just derive from both classes
47No Problem?
- Well, first of all, we have conceptual problems.
Consider - Start with type A
- Derive types A1 and A2 from A
- Now derive type B from A1 and A2
- Do we have two As around, or only one
- Sometimes we want one, sometimes the other, and
almost always this causes confusion.
48No Problem? (part 2)
- Second, it causes implementation difficulties.
- The wonderful trick for the single inheritance
case was that if type A is derived from type B,
directly or indirectly, it has an A at the start,
allowing uniform treatment. - But this model does not extend to more than one
parent ?
49Multiple Inheritance
- C implements multiple inheritance
- Some kludgy semantics to deal with the confusing
duplication case - Some kludge implementation to deal with the
implementation issues (which incidentally causes
distributed overhead in the non-MI case,
basically you carry around an offset to the
parent field which is always zero for single
inheritance)
50Most OO Languages Avoid MI
- How can we get effect of MI with no MI
- Two answers
- Generic mixins. Suppose our node example instead
of being nodes of integers is nodes of type T,
then when we instantiate type T, the nodes have
the operations of type T available. - Interfaces. If an operation requires only
Compare/Move, then we can allow it to be used on
any class which has these methods (rather than
requiring those classes to be derived from a
common Comparable class). So introduce the notion
of Comparable Interface.
51Going Even Further towards OO
- Languages like Small Talk and Ruby really insist
on everything being an object, even integers and
floats - You can still do manual procedural programming
but it gets harder and harder.
52How Far Should we Go
- Not everything fits the OO paradigm
- Suppose we have a package providing a type
Large_Integer with the usual arithmetic
operations. - Now derive Colored_Large_Integers
- That works fine in Ada, we just get a new
that works on CLIs - But in the OO languages this is not so clear.
- On the other hand, prefix notation and implied
this is definitely nice for OOD. - Ada may allow prefix notation in future ?