You are on page 1of 64

Hiding Data within Object-Oriented Programming

 July 29, 2004


 By Matt Weisfeld
 Bio »
 Send Email »
 More Articles »

Introduction
This is the seventh installment in a series of articles about fundamental object-oriented (OO)
concepts. The material presented in these articles is based on material from the second edition of my
book, The Object-Oriented Thought Process, 2nd edition. The Object-Oriented Thought Process is
intended for anyone who needs to understand the basic object-oriented concepts before jumping into
the code. Click here to start at the beginning of the series.

Now that we have covered the conceptual basics of classes and objects, we can start to explore
specific concepts in more detail. Remember that there are three criteria that are applied to object-
oriented languages: They have to implement encapsulation, inheritance, and polymorphism. Of
course, these are not the only important terms, but they are a great place to start a discussion.

In the previous article, this article, and several of the ones that follow, we will focus on a single
concept and explore how it fits in to the object-oriented model. We will also begin to get much more
involved with code. In keeping with the code examples used in the previous articles, Java will be the
language used to implement the concepts in code. One of the reasons that I like to use Java is
because you can download the Java compiler for personal use at the Sun Microsystems Web
site http://java.sun.com/. You can download the J2SE 1.4.2 SDK (software development kit) to
compile and execute these applications and will provide the code listings for all examples in this
article. I have the SDK 1.4.0 loaded on my machine. I will provide figures and the output for these
examples. See the previous article in this series for detailed descriptions for compiling and running all
the code examples in this series.

Checking Account Example


Recall that in the previous article, we created a class diagram that is represented in the following UML
diagram; see Figure 1.

 Post a comment
 Email Article
 Print Article
  Share Articles

Figure 1: UML Diagram for Checking Account Class


This class is designed to illustrate the concept of encapsulation. This class encapsulates both the
data (attributes) and methods (behaviors). Encapsulation is a fundamental concept of object-oriented
design—all objects contain both attributes and behavior. The UML class diagram is composed of only
three parts: the class name, the attributes, and the behaviors. This class diagram maps directly to the
code in Listing 1.

class CheckingAccount {
private double balance = 0;
public void setBalance(double bal) {
balance = bal;
};
public double getBalance(){
return balance;
};
}

Listing 1: CheckingAccount.java

This direct mapping from class diagram to code (and back) is another important issue when designing
classes. This mapping not only helps with the design of the class, but also with the maintenance of
the class. Multiple class diagrams are used to design an object-oriented system and make up what is
termed an object model. Object models will be discussed at length in later articles.

Once a system is complete, the documentation pertaining to the design is obviously very important.
The deployment of a new application marks the beginning of the maintenance phase, which will
continue for the lifetime of the application and contain many, many bug fixes, updates, and
enhancements to the system. While the object-model is a great design tool, it is also a great
maintenance tool.

However, as with all documentation, an object model that is not updated as the application changes is
at best useless, and at worst misleading. Anyone who has used flowcharts knows exactly what the
problem is. For example, consider an application that is deployed with flow charts included in the final
documentation. If a bug is identified and fixed in the code, unless the change in logic is retrofitted to
the flow chart, the flow chart is out of date and does not represent the current application. In the
future, when another programmer, or perhaps even the original programmer, revisits the
documentation, it can be misleading. This may lead to a major problem. The same problem can occur
when classes change and the class diagram is not updated properly to reflect the changes.

Why have we taken this interlude about updating documentation at this point? Because there now are
tools to manage much of the documentation process and I believe that anyone wanting to learn
object-oriented design must integrate the knowledge of these tools into their thought process as early
as possible. In short, the process of creating class diagrams and mapping them directly to code (and
back) is tracked, and somewhat controlled, by software tools. In future articles, we will get into much
more detail about the tools themselves. Right now, just be aware that the class diagrams and the
code are tightly coupled.
Note: Some of the products that can help with the process are Rational Rose, owned by IBM and
Visio, owned by Microsoft.

Data Hiding
Returning to the actual CheckingAccount example, we can see that while the class contains both
attributes and behavior, not all of the class is accessible to other class. For example, consider again
the balance attribute. Note that balance is defined as private.

private double balance = 0;

We proved in the last article that attempting to access this attribute directly from an application would
produce an error. The application that produces this error is shown in Listing 2.

class Encapsulation {

public static void main(String args[]) {


System.out.println("Starting myEncapsulation...");
CheckingAccount myAccount = new CheckingAccount();
myAccount.balance = 40.00;
System.out.println("Balance = " + myAccount.getBalance());
}

Listing 2: Encapsulation.java

The offending line is the where this main application attempts to set balance directly.

myAccount.balance = 40.00;

This line violates the rule of data hiding. As we saw in last month's article, the compiler does not allow
this; however, it fails to set balance to 40 only because the access was declared as private. It is
interesting to note that the Java language, just as C++, C#, and other languages, allows for the
attribute to be declared as public. In this case, the main application would indeed be allowed to
directly set the value of balance. This then would break the object-oriented concept of data hiding and
would not be considered a proper object-oriented design.

This is one area where the importance of the design comes in. If you abide by the rule that all
attributes are private, all attributes of an object are hidden, thus the term data hiding. This is so
important because the compiler now can enforce the data hiding rule. If you declare all of a class's
attributes as private, a rogue developer cannot directly access the attributes from an application.
Basically, you get this protection checking for free.

Whereas the class's attributes are hidden, the methods in this example are designated as public.
public void setBalance(double bal) {
balance = bal;
};
public double getBalance(){
return balance;

};

Object Oriented Programming Concepts

3.1 Introduction

The use of Object Oriented (OO) design and Object Oriented Programming (OOP) are becoming
increasingly popular. Thus, it is useful to have an introductory understanding of OOP and some of
the

programming features of OO languages. You can develop OO software in any high level language,
like

C or Pascal. However, newer languages such as Ada, C++, and F90 have enhanced features that make

OOP much more natural, practical, and maintainable. C++ appeared before F90 and currently, is
probably the most popular OOP language, yet F90 was clearly designed to have almost all of the
abilities of

C++ . However, rather than study the new standards many authors simply refer to the two decades
old

F77 standard and declare that Fortran can not be used for OOP. Here we will overcome that
misinformed

point of view.

Modern OO languages provide the programmer with three capabilities that improve and simplify

the design of such programs: encapsulation, inheritance, and polymorphism (or generic
functionality).

Related topics involve objects, classes, and data hiding. An object combines various classical data
types

into a set that defines a new variable type, or structure. A class unifies the new entity types and
supporting
data that represents its state with routines (functions and subroutines) that access and/or modify
those

data. Every object created from a class, by providing the necessary data, is called an instance of the

class. In older languages like C and F77, the data and functions are separate entities. An OO language

provides a way to couple or encapsulate the data and its functions into a unified entity. This is a
more

natural way to model real-world entities which have both data and functionality. The encapsulation
is

done with a “module” block in F90, and with a “class” block in C++. This encapsulation also includes

a mechanism whereby some or all of the data and supporting routines can be hidden from the user.
The

accessibility of the specifications and routines of a class is usually controlled by optional “public” and

“private” qualifiers. Data hiding allows one the means to protect information in one part of a
program

from access, and especially from being changed in other parts of the program. In C++ the default is

that data and functions are “private” unless declared “public,” while F90 makes the opposite choice
for

its default protection mode. In a F90 “module” it is the “contains” statement that, among other
things,

couples the data, specifications, and operators before it to the functions and subroutines that follow
it.

Class hierarchies can be visualized when we realize that we can employ one or more previously

defined classes (of data and functionality) to organize additional classes. Functionality programmed
into

the earlier classes may not need to be re-coded to be usable in the later classes. This mechanism is
called

inheritance. For example, if we have defined an Employee class, thena Manager class would

inherit all of the data and functionality of an employee. We would then only be required to add only

the totally new data and functions needed for a manager. We may also need a mechanism to re-
define

specific Employee class functions that differ for a Manager class. By using the concept of a class
hierarchy, less programming effort is required to create the final enhanced program. In F90 the
earlier

class is brought into the later class hierarchy by the “use” statement followed by the name of the
“module”

statement block that defined the class.

Polymorphism allows different classes of objects that share some common functionality to be used
in

code that requires only that common functionality. In other words, routines having the same generic
name
c 2001 J.E. Akin 33are interpreted differently depending on the class of the objects presented as
arguments to the routines.

This is useful in class hierarchies where a small number of meaningful function names can be used to

manipulate different, but related object classes. The above concepts are those essential to object
oriented

design and OOP. In the later sections we will demonstrate by example additional F90
implementations

of these concepts.

3.2 Encapsulation, Inheritance, and Polymorphism

We often need to use existing classes to define new classes. The two ways to do this are called
composition

and inheritance. We will use both methods in a series of examples. Consider a geometry program

that uses two different classes: class Circle and class Rectangle, as represented graphically in

Figs. 3.1 and 3.2. and as partially implemented in F90 as shown in Fig. 3.3. Each class shown has the

data types and specifications to define the object and the functionality to compute their respective
areas

(lines 3–22). The operator % is employed to select specific components of a defined type. Within the

geometry (main) program a single routine, compute area, is invoked (lines 38 and 44) to return the

area for any of the defined geometry classes. That is, a generic function name is used for all classes

of its arguments and it, in turn, branches to the corresponding functionality supplied with the
argument

class. To accomplish this branching the geometry program first brings in the functionality of the
desired
classes via a “use” statement for each class module (lines 25 and 26). Those “modules” are coupled
to

the generic function by an “interface” block which has the generic function name compute area
(lines

28, 29). There is included a “module procedure” list which gives one class routine name for each of
the

classes of argument(s) that the generic function is designed to accept. The ability of a function to
respond

differently when supplied with arguments that are objects of different types is called polymorphism.

In this example we have employed different names, rectangular area and circle area, in their

respective class modules, but that is not necessary. The “use” statement allows one to rename the
class

routines and/or to bring in only selected members of the functionality.

Circle Class

radius

make_Circle

real

real pi

Circle

real

Circle

Circle_Area

Circle

Figure 3.1: Representation of a Circle Class

Another terminology used in OOP is that of constructors and destructors for objects. An intrinsic

constructor is a system function that is automatically invoked when an object is declared with all of
its

possible components in the defined order (see lines 37 and 43). In C++, and F90 the intrinsic
constructor

has the same name as the “type” of the object. One is illustrated in the statement
four sides = Rectangle (2.1,4.3)

where previously we declared

type (Rectangle) :: four sides

which, in turn, was coupled to the class Rectangle which had two components, base and height,

defined in that order, respectively. The intrinsic constructor in the example statement sets
component
c 2001 J.E. Akin 34Figure 3.2: Representation of a Rectangle Class

[ 1] ! Areas of shapes of different classes, using different

[ 2] ! function names in each class

[ 3] module class Rectangle ! define the first object class

[ 4] implicit none

[ 5] type Rectangle

[ 6] real :: base, height ; end type Rectangle

[ 7] contains ! Computation of area for rectangles.

[ 8] function rectangle area ( r ) result ( area )

[ 9] type ( Rectangle ), intent(in) :: r

[10] real :: area

[11] area = r%base * r%height ; end function rectangle area

[12] end module class Rectangle

[13]

[14] module class Circle ! define the second object class

[15] real :: pi = 3.1415926535897931d0 ! a circle constant

[16] type Circle

[17] real :: radius ; end type Circle

[18] contains ! Computation of area for circles.

[19] function circle area ( c ) result ( area )

[20] type ( Circle ), intent(in) :: c

[21] real :: area


[22] area = pi * c%radius**2 ; end function circle area

[23] end module class Circle

[24]

[25] program geometry ! for both types in a single function

[26] use class Circle

[27] implicit none

[28] use class Rectangle

[29] ! Interface to generic routine to compute area for any type

[30] interface compute area

[31] module procedure rectangle area, circle area ; end interface

[32]

[33] ! Declare a set geometric objects.

[34] type ( Rectangle ) :: four sides

[35] type ( Circle ) :: two sides ! inside, outside

[36] real :: area = 0.0 ! the result

[37]

[38] ! Initialize a rectangle and compute its area.

[39] four sides = Rectangle ( 2.1, 4.3 ) ! implicit constructor

[40] area = compute area ( four sides ) ! generic function

[41] write ( 6,100 ) four sides, area ! implicit components list

[42] 100 format ("Area of ",f3.1," by ",f3.1," rectangle is ",f5.2)

[43]

[44] ! Initialize a circle and compute its area.

[45] two sides = Circle ( 5.4 ) ! implicit constructor

[46] area = compute area ( two sides ) ! generic function

[47] write ( 6,200 ) two sides, area

[48] 200 format ("Area of circle with ",f3.1," radius is ",f9.5 )


[49] end program geometry ! Running gives:

[50] ! Area of 2.1 by 4.3 rectangle is 9.03

[51] ! Area of circle with 5.4 radius is 91.60885

Figure 3.3: Multiple Geometric Shape Classes

base = 2.1 and component height = 4.3 for that instance, four sides, of the type Rectangle.

This intrinsic construction is possible because all the expected components of the type were
supplied. If

all the components are not supplied, then the object cannot be constructed unless the functionality
of the
c 2001 J.E. Akin 35[ 1] function make Rectangle (bottom, side) result (name)

[ 2] ! Constructor for a Rectangle type

[ 3] implicit none

[ 4] real, optional, intent(in) :: bottom, side

[ 5] type (Rectangle) :: name

[ 6] name = Rectangle (1.,1.) ! default to unit square

[ 7] if ( present(bottom) ) then ! default to square

[ 8] name = Rectangle (bottom, bottom) ; end if

[ 9] if ( present(side) ) name = Rectangle (bottom, side) ! intrinsic

[10] end function make Rectangle

[11] . . .

[12] type ( Rectangle ) :: four sides, square, unit sq

[13] ! Test manual constructors

[14] four sides = make Rectangle (2.1,4.3) ! manual constructor, 1

[15] area = compute area ( four sides) ! generic function

[16] write ( 6,100 ) four sides, area

[17] ! Make a square

[18] square = make Rectangle (2.1) ! manual constructor, 2

[19] area = compute area ( square) ! generic function

[20] write ( 6,100 ) square, area


[21] ! "Default constructor", here a unit square

[22] unit sq = make Rectangle () ! manual constructor, 3

[23] area = compute area (unit sq) ! generic function

[24] write ( 6,100 ) unit sq, area

[25] . . .

[26] ! Running gives:

[27] ! Area of 2.1 by 4.3 rectangle is 9.03

[28] ! Area of 2.1 by 2.1 rectangle is 4.41

[29] ! Area of 1.0 by 1.0 rectangle is 1.00

Figure 3.4: A Manual Constructor for Rectangles

class is expanded by the programmer to accept a different number of arguments.

Assume that we want a special member of the Rectangle class, a square, to be constructed if the

height is omitted. That is, we would use height = base in that case. Or, we may want to construct a

unit square if both are omitted so that the constructor defaults to base = height = 1. Such a manual

constructor, named make Rectangle, is illustrated in Fig. 3.4 (see lines 5, 6). It illustrates some

additional features of F90. Note that the last two arguments were declared to have the additional
type

attributes of “optional” (line 3), and that an associated logical function “present” is utilized (lines 6
and 8)

to determine if the calling program supplied the argument in question. That figure also shows the
results

of the area computations for the corresponding variables “square” and “unit sq” defined if the
manual

constructor is called with one or no optional arguments (line 5), respectively.

In the next section we will illustrate the concept of data hiding by using the private attribute. The

reader is warned that the intrinsic constructor can not be employed if any of its arguments have
been

hidden. In that case a manual constructor must be provided to deal with any hidden components.
Since

data hiding is so common it is probably best to plan on prividing a manual constructor.


3.2.1 Example Date, Person, and Student Classes

Beforemoving to some mathematical exampleswe will introduce the concept of data hiding and
combine

a series of classes to illustrate composition and inheritancey

First, consider a simple class to define dates .

and to print them in a pretty fashion, as shown in Figs. 3.5 and 3.6. While other modules will have

access to the Date class they will not be given access to the number of components it contains (3),

nor their names (month, day, year), nor their types (integers) because they are declared “private” in
the

defining module (lines 5 and 6). The compiler will not allow external access to data and/or routines

declared as private. The module, class Date, is presented as a source “include” file in Fig. 3.6, and

in the future will be reference by the file name class Date.f90. Since we have chosen to hide all

the user defined components we must decide what functionality we will provide to the users, who
may

have only executable access. The supporting documentation would have to name the public routines
and

describe their arguments and return results. The default intrinsic constructor would be available only
to y

those that know full details about the components of the data type, and if those components are
“public.”

These examples mimic those given in Chapter 11 and 8 of the J.R. Hubbard book “Programming with
C++,” McGraw-Hill,

1994, and usually use the same data for verification.


c 2001 J.E. Akin 36Date Class

month

Date_

integer

integer day

Date

Date

Date
Print_Date

Date

integer year

Date Read_Date

Date Set_Date

Figure 3.5: Graphical Representation of a Date Class

The intrinsic constructor, Date (lines 14 and 34), requires all the components be supplied, but it does

no error or consistency checks. My practice is to also define a “public constructor” whose name is
the

same as the intrinsic constructor except for an appended underscore, that is, Date . Its sole purpose
is to

do data checking and invoke the intrinsic constructor, Date. If the function Date (line 10) is declared

“public” it can be used outside the module class Date to invoke the intrinsic constructor, even if the

components of the data type being constructed are all “private.” In this examplewe have provided
another

manual constructor to set a date, set Date (line 31),with a variable number of optional arguments.
Also

supplied are two subroutines to read and print dates, read Date (line 27) and print Date (line 16),

respectively.

A sample main program that employs this class is given in Fig. 3.7, which contains sample outputs

as comments. This program uses the default constructor as well as all three programs in the public
class

functionality. Note that the definition of the class was copied in via an “include” (line 1) statement
and

activated with the “use” statement (line 4).

Now we will employ the class Date within a class Person which will use it to set the date of

birth (DOB) and date of death (DOD) in addition to the other Person components of name,
nationality, and sex. As shown in Fig. 3.8, we have made all the type components “private,” but
make all the

supporting functionality public, as represented graphically in Fig. 3.8. The functionality shown
provides
a manual constructor, make Person, routines to set the DOB or DOD, and those for the printing of

most components. The source code for the new Person class is given in Fig. 3.9. Note that the
manual

constructor (line 12) utilizes “optional” arguments and initializes all components in case they are not

supplied to the constructor. The Date public function from the class Date is “inherited” to initialize
the DOB and DOD (lines 18, 57, and 62). That function member from the previous module was

activated with the combination of the “include” and “use” statements. Of course, the include could
have

been omitted if the compile statement included the path name to that source. A sample main
program

for testing the class Person is in Fig. 3.10 along with comments containing its output. It utilizes the

constructors Date (line 7), Person (line10), and make Person (line 24).

Next, we want to use the previous two classes to define a class Student which adds something

else special to the general class Person. The student person will have additional “private”
components for an identification number, the expected date ofmatriculation (DOM), the total course
credit hours

earned (credits), and the overall grade point average (GPA), as represented in Fig. 3.11. The source
lines

for the type definition and selected public functionality are given in Fig. 3.12. There the constructors

are make Student (line 19) and Student (line 47). A testing main program with sample output is

illustrated in Fig. 3.13. Since there are various ways to utilize the various constructors three alternate

methods have been included as comments to indicate some of the programmers options. The first
two

include statements (lines 1, 2) are actually redundant because the third include automatically brings

in those first two classes.


c 2001 J.E. Akin 37[ 1] module class Date ! filename: class Date.f90

[ 2] implicit none

[ 3] public :: Date ! and everything not "private"

[ 4]

[ 5] type Date

[ 6] private
[ 7] integer :: month, day, year ; end type Date

[ 8]

[ 9] contains ! encapsulated functionality

[10]

[11] function Date (m, d, y) result (x) ! public constructor

[12] integer, intent(in) :: m, d, y ! month, day, year

[13] type (Date) :: x ! from intrinsic constructor

[14] if ( m < 1 .or. d < 1 ) stop ’Invalid components, Date ’

[15] x = Date (m, d, y) ; end function Date

[16]

[17] subroutine print Date (x) ! check and pretty print a date

[18] type (Date), intent(in) :: x

[19] character (len=*),parameter :: month Name(12) = &

[20] (/ "January ", "February ", "March ", "April ",&

[21] "May ", "June ", "July ", "August ",&

[22] "September", "October ", "November ", "December "/)

[23] if ( x%month < 1 .or. x%month > 12 ) print *, "Invalid month"

[24] if ( x%day < 1 .or. x%day > 31 ) print *, "Invalid day "

[25] print *, trim(month Name(x%month)),’ ’, x%day, ", ", x%year;

[26] end subroutine print Date

[27]

[28] subroutine read Date (x) ! read month, day, and year

[29] type (Date), intent(out) :: x ! into intrinsic constructor

[30] read *, x ; end subroutine read Date

[31]

[32] function set Date (m, d, y) result (x) ! manual constructor

[33] integer, optional, intent(in) :: m, d, y ! month, day, year


[34] type (Date) :: x

[35] x = Date (1,1,1997) ! default, (or use current date)

[36] if ( present(m) ) x%month = m ; if ( present(d) ) x%day = d

[37] if ( present(y) ) x%year = y ; end function set Date

[38]

[39] end module class Date

Figure 3.6: Defining a Date Class

[ 1] include ’class Date.f90’ ! see previous figure

[ 2] program main

[ 3] use class Date

[ 4] implicit none

[ 5] type (Date) :: today, peace

[ 6]

[ 7] ! peace = Date (11,11,1918) ! NOT allowed for private components

[ 8] peace = Date (11,11,1918) ! public constructor

[ 9] print *, "World War I ended on " ; call print Date (peace)

[10] peace = set Date (8, 14, 1945) ! optional constructor

[11] print *, "World War II ended on " ; call print Date (peace)

[12] print *, "Enter today as integer month, day, and year: "

[13] call read Date(today) ! create today’s date

[14]

[15] print *, "The date is "; call print Date (today)

[16] end program main ! Running produces:

[17] ! World War I ended on November 11, 1918

[18] ! World War II ended on August 14, 1945

[19] ! Enter today as integer month, day, and year: 7 10 1997

[20] ! The date is July 10, 1997


Figure 3.7: Testing a Date Class

3.3 Object Oriented Numerical Calculations

OOP is often used for numerical computation, especially when the standard storage mode for arrays
is

not practical or efficient. Often one will find specialized storage modes like linked lists, or tree
structures

used for dynamic data structures. Here we should note that many matrix operators are intrinsic to
F90,

so one is more likely to define a class sparse matrix than a class matrix. However, either

class would allow us to encapsulate several matrix functions and subroutines into a module that
could be

reused easily in other software. Here, we will illustrate OOP applied to rational numbers and
introduce
c 2001 J.E. Akin 38Person Class

name

Person_

character

character nationality

Person

Person

Person

make_Person

Person

integer sex

Person print_DOB

Person print_DOD

Date Date_Of_Birth

Date Date_Of_Death

Person print_Name

Person print_Nationality
Person print_Sex

Person set_DOB

Person set_DOD

Figure 3.8: Graphical Representation of a Person Class

the important topic of operator overloading. Additional numerical applications of OOP will be
illustrated

in later chapters.

3.3.1 A Rational Number Class and Operator Overloading

To illustrate an OOP approach to simple numerical operations we will introduce a fairly complete
rational

number class, called class Rational which is represented graphically in Fig. 3.14. The defining F90

module is given in Fig. 3.15. The type components have been made private (line 5), but not the type

itself, so we can illustrate the intrinsic constructor (lines 38 and 102), but extra functionality has
been

provided to allow users to get either of the two components (lines 52 and 57). The provided routines

shown in that figure are:

add Rational convert copy Rational delete Rational

equal integer gcd get Denominator get Numerator

invert is equal to list make Rational

mult Rational Rational reduce

Procedures with only one return argument are usually implemented as functions instead of
subroutines.

Note that we would form a new rational number,z , as the product of two other rational numbers,x

andy , by invoking the mult Rational function (line 90),

z = mult Rational (x, y)

which returnsz as its result. A natural tendency at this point would be to simply write this asz =

x y . However, before we could do that we would have to have to tell the operator, “*”, how to act

when provided with this new data type. This is known as overloading an intrinsic operator. We had
the
foresight to do this when we set up the module by declaring which of the “module procedures” were

equivalent to this operator symbol. Thus, from the “interface operator (*)” statement block (line 14)

the system now knows that the left and right operands of the “*” symbol correspond to the first and

second arguments in the function mult Rational. Here it is not necessary to overload the assignment

operator, “=”, when both of its operands are of the same intrinsic or defined type. However, to
convert
c 2001 J.E. Akin 39[ 1] module class Person ! filename: class Person.f90

[ 2] use class Date

[ 3] implicit none

[ 4] public :: Person

[ 5] type Person

[ 6] private

[ 7] character (len=20) :: name

[ 8] character (len=20) :: nationality

[ 9] integer :: sex

[10] type (Date) :: dob, dod ! birth, death

[11] end type Person

[12] contains

[13] function make Person (nam, nation, s, b, d) result (who)

[14] ! Optional Constructor for a Person type

[15] character (len=*), optional, intent(in) :: nam, nation

[16] integer, optional, intent(in) :: s ! sex

[17] type (Date), optional, intent(in) :: b, d ! birth, death

[18] type (Person) :: who

[19] who = Person (" ","USA",1,Date (1,1,0),Date (1,1,0)) ! defaults

[20] if ( present(nam) ) who % name = nam

[21] if ( present(nation) ) who % nationality = nation

[22] if ( present(s) ) who % sex = s


[23] if ( present(b) ) who % dob = b

[24] if ( present(d) ) who % dod = d ; end function

[25]

[26] function Person (nam, nation, s, b, d) result (who)

[27] ! Public Constructor for a Person type

[28] character (len=*), intent(in) :: nam, nation

[29] integer, intent(in) :: s ! sex

[30] type (Date), intent(in) :: b, d ! birth, death

[31] type (Person) :: who

[32] who = Person (nam, nation, s, b, d) ; end function Person

[33]

[34] subroutine print DOB (who)

[35] type (Person), intent(in) :: who

[36] call print Date (who % dob) ; end subroutine print DOB

[37]

[38] subroutine print DOD (who)

[39] type (Person), intent(in) :: who

[40] call print Date (who % dod) ; end subroutine print DOD

[41]

[42] subroutine print Name (who)

[43] type (Person), intent(in) :: who

[44] print *, who % name ; end subroutine print Name

[45]

[46] subroutine print Nationality (who)

[47] type (Person), intent(in) :: who

[48] print *, who % nationality ; end subroutine print Nationality

[49]
[50] subroutine print Sex (who)

[51] type (Person), intent(in) :: who

[52] if ( who % sex == 1 ) then ; print *, "male"

[53] else ; print *, "female" ; end if ; end subroutine print Sex

[54]

[55] subroutine set DOB (who, m, d, y)

[56] type (Person), intent(inout) :: who

[57] integer, intent(in) :: m, d, y ! month, day, year

[58] who % dob = Date (m, d, y) ; end subroutine set DOB

[59]

[60] subroutine set DOD(who, m, d, y)

[61] type (Person), intent(inout) :: who

[62] integer, intent(in) :: m, d, y ! month, day, year

[63] who % dod = Date (m, d, y) ; end subroutine set DOD

[64] end module class Person

Figure 3.9: Definition of a Typical Person Class

an integer to a rational we could, and have, defined an overloaded assignment operator procedure
(line

10). Here we have provided the procedure, equal Integer, which is automatically invoked when

we write : type(Rational)y; y = 4. That would be simpler than invoking the constructor called

make rational. Before moving on note that the system does not yet know how to multiply an integer

times a rational number, or visa versa. To do that one would have to add more functionality, such as
a

function, say int mult rn, and add it to the “module procedure” list associated with the “*” operator.

A typical main program which exercises most of the rational number functionality is given in Fig.
3.16,

along with typical numerical output. It tests the constructors Rational (line 8), make Rational
c 2001 J.E. Akin 40[ 1] include ’class Date.f90’

[ 2] include ’class Person.f90’ ! see previous figure


[ 3] program main

[ 4] use class Date ; use class Person ! inherit class members

[ 5] implicit none

[ 6] type (Person) :: author, creator

[ 7] type (Date) :: b, d ! birth, death

[ 8] b = Date (4,13,1743) ; d = Date (7, 4,1826) ! OPTIONAL

[ 9] ! Method 1

[10] ! author = Person ("Thomas Jefferson", "USA", 1, b, d) ! NOT if private

[11] author = Person ("Thomas Jefferson", "USA", 1, b, d) ! constructor

[12] print *, "The author of the Declaration of Independence was ";

[13] call print Name (author);

[14] print *, ". He was born on "; call print DOB (author);

[15] print *, " and died on "; call print DOD (author); print *, ".";

[16] ! Method 2

[17] author = make Person ("Thomas Jefferson", "USA") ! alternate

[18] call set DOB (author, 4, 13, 1743) ! add DOB

[19] call set DOD (author, 7, 4, 1826) ! add DOD

[20] print *, "The author of the Declaration of Independence was ";

[21] call print Name (author)

[22] print *, ". He was born on "; call print DOB (author);

[23] print *, " and died on "; call print DOD (author); print *, ".";

[24] ! Another Person

[25] creator = make Person ("John Backus", "USA") ! alternate

[26] print *, "The creator of Fortran was "; call print Name (creator);

[27] print *, " who was born in "; call print Nationality (creator);

[28] print *, ".";

[29] end program main ! Running gives:


[30] ! The author of the Declaration of Independence was Thomas Jefferson.

[31] ! He was born on April 13, 1743 and died on July 4, 1826.

[32] ! The author of the Declaration of Independence was Thomas Jefferson.

[33] ! He was born on April 13, 1743 and died on July 4, 1826.

[34] ! The creator of Fortran was John Backus who was born in the USA.

Figure 3.10: Testing the Date and Person Classes

Student Class

who

Student_

Person

character id [SSN]

Student

Student

Student

make_Student

Student

Date matriculation

Student get_Person

Student print_DOM

integer credits

real gpa

Student print_GPA

Student set_DOM

Figure 3.11: Graphical Representation of a Student Class

(lines 14, 18, 25), and a simple destructor delete Rational (line 38). The intrinsic constructor (line

6) could have been used only if all the attributes were public, and that is considered an undesirable

practice in OOP. The simple destructor actually just sets the “deleted” number to have a set of
default
components. Later we will see that constructors and destructors often must dynamically allocate
and

deallocate, respectively, memory associated with a specific instance of some object.


c 2001 J.E. Akin 41[ 1] module class Student ! filename class Student.f90

[ 2] use class Person ! inherits class Date

[ 3] implicit none

[ 4] public :: Student, set DOM, print DOM

[ 5] type Student

[ 6] private

[ 7] type (Person) :: who ! name and sex

[ 8] character (len=9) :: id ! ssn digits

[ 9] type (Date) :: dom ! matriculation

[10] integer :: credits

[11] real :: gpa ! grade point average

[12] end type Student

[13] contains ! coupled functionality

[14]

[15] function get person (s) result (p)

[16] type (Student), intent(in) :: s

[17] type (Person) :: p ! name and sex

[18] p = s % who ; end function get person

[19]

[20] function make Student (w, n, d, c, g) result (x) ! constructor

[21] ! Optional Constructor for a Student type

[22] type (Person), intent(in) :: w ! who

[23] character (len=*), optional, intent(in) :: n ! ssn

[24] type (Date), optional, intent(in) :: d ! matriculation

[25] integer, optional, intent(in) :: c ! credits


[26] real, optional, intent(in) :: g ! grade point ave

[27] type (Student) :: x ! new student

[28] x = Student (w, " ", Date (1,1,1), 0, 0.) ! defaults

[29] if ( present(n) ) x % id = n ! optional values

[30] if ( present(d) ) x % dom = d

[31] if ( present(c) ) x % credits = c

[32] if ( present(g) ) x % gpa = g ; end function make Student

[33]

[34] subroutine print DOM (who)

[35] type (Student), intent(in) :: who

[36] call print Date(who%dom) ; end subroutine print DOM

[37]

[38] subroutine print GPA (x)

[39] type (Student), intent(in) :: x

[40] print *, "My name is "; call print Name (x % who)

[41] print *, ", and my G.P.A. is ", x % gpa, "." ; end subroutine

[42]

[43] subroutine set DOM (who, m, d, y)

[44] type (Student), intent(inout) :: who

[45] integer, intent(in) :: m, d, y

[46] who % dom = Date ( m, d, y) ; end subroutine set DOM

[47]

[48] function Student (w, n, d, c, g) result (x)

[49] ! Public Constructor for a Student type

[50] type (Person), intent(in) :: w ! who

[51] character (len=*), intent(in) :: n ! ssn

[52] type (Date), intent(in) :: d ! matriculation


[53] integer, intent(in) :: c ! credits

[54] real, intent(in) :: g ! grade point ave

[55] type (Student) :: x ! new student

[56] x = Student (w, n, d, c, g) ; end function Student

[57] end module class Student

Figure 3.12: Defining a Typical Student Class

When considering which operators to overload for a newly defined object one should consider those

that are used in sorting operations, such as the greater-than,>, and less-than,<, operators. They are

often useful because of the need to sort various types of objects. If those symbols have been
correctly

overloaded then a generic object sorting routine might be used, or require few changes.

3.4 Discussion

The previous sections have only briefly touched on some important OOP concepts. More details will
be

covered later after a general overview of the features of the Fortran language. There are more than
one

hundred OOP languages. Persons involved in software development need to be aware that F90 can
meet

almost all of their needs for a OOP language. At the same time it includes the F77 standard as a
subset

and thus allows efficient use of the many millions of Fortran functions and subroutines developed in
the

past. The newer F95 standard is designed to make efficient use of super computers and massively
parallel
c 2001 J.E. Akin 42[ 1] include ’class Date.f90’

[ 2] include ’class Person.f90’

[ 3] include ’class Student.f90’ ! see previous figure

[ 4] program main ! create or correct a student

[ 5] use class Student ! inherits class Person, class Date also

[ 6] implicit none

[ 7] type (Person) :: p ; type (Student) :: x


[ 8] ! Method 1

[ 9] p = make Person ("Ann Jones","",0) ! optional person constructor

[10] call set DOB (p, 5, 13, 1977) ! add birth to person data

[11] x = Student (p, "219360061", Date (8,29,1955), 9, 3.1) ! public

[12] call print Name (p) ! list name

[13] print *, "Born :"; call print DOB (p) ! list dob

[14] print *, "Sex :"; call print Sex (p) ! list sex

[15] print *, "Matriculated:"; call print DOM (x) ! list dom

[16] call print GPA (x) ! list gpa

[17] ! Method 2

[18] x = make Student (p, "219360061") ! optional student constructor

[19] call set DOM (x, 8, 29, 1995) ! correct matriculation

[20] call print Name (p) ! list name

[21] print *, "was born on :"; call print DOB (p) ! list dob

[22] print *, "Matriculated:"; call print DOM (x) ! list dom

[23] ! Method 3

[24] x = make Student (make Person("Ann Jones"), "219360061") ! optional

[25] p = get Person (x) ! get defaulted person data

[26] call set DOM (x, 8, 29, 1995) ! add matriculation

[27] call set DOB (p, 5, 13, 1977) ! add birth

[28] call print Name (p) ! list name

[29] print *, "Matriculated:"; call print DOM (x) ! list dom

[30] print *, "was born on :"; call print DOB (p) ! list dob

[31] end program main ! Running gives:

[32] ! Ann Jones

[33] ! Born : May 13, 1977

[34] ! Sex : female


[35] ! Matriculated: August 29, 1955

[36] ! My name is Ann Jones, and my G.P.A. is 3.0999999.

[37] ! Ann Jones was born on: May 13, 1977 , Matriculated: August 29, 1995

[38] ! Ann Jones Matriculated: August 29, 1995 , was born on: May 13, 1977

Figure 3.13: Testing the Student, Person, and Date Classes

machines. It includes most of the High Performance Fortran features that are in wide use. Thus,
efficient

use of OOP on parallel machines is available through F90 and F95.

None of the OOP languages have all the features one might desire. For example, the useful concept

of a “template” which is standard in C++ is not in the F90 standard. Yet the author has found that a

few dozen lines of F90 code will define a preprocessor that allows templates to be defined in F90
and

expanded in line at compile time. The real challenge in OOP is the actual OOA and OOD that must be

completed before programming can begin, regardless of the language employed. For example,
several

authors have described widely different approaches for defining classes to be used in constructing
OO

finite element systems. Additional example applications of OOP in F90 will be given in the following

chapters.
c 2001 J.E. Akin 43Rational Class

numerator

Rational_

integer

Rational

Rational

Rational

make_Rational

reduce

Rational add_Rational
Rational convert

integer denominator

Rational copy_Rational

Rational is_equal_to

integer gcd

Rational Rational

Rational list

Rational mult_Rational

Rational invert

Rational delete_Rational

Rational equal_Rational

Rational get_Denominator

Rational get_Numerator

Figure 3.14: Representation of a Rational Number Class


c 2001 J.E. Akin 44[ 1] module class Rational ! filename: class Rational.f90

[ 2] implicit none

[ 3] ! public, everything but following private routines

[ 4] private :: gcd, reduce

[ 5] type Rational

[ 6] private ! numerator and denominator

[ 7] integer :: num, den ; end type Rational

[ 8]

[ 9] ! overloaded operators interfaces

[ 10] interface assignment (=)

[ 11] module procedure equal Integer ; end interface

[ 12] interface operator (+) ! add unary versions & (-) later

[ 13] module procedure add Rational ; end interface

[ 14] interface operator (*) ! add integer mult Rational, etc


[ 15] module procedure mult Rational ; end interface

[ 16] interface operator (==)

[ 17] module procedure is equal to ; end interface

[ 18] contains ! inherited operational functionality

[ 19] function add Rational (a, b) result (c) ! to overload +

[ 20] type (Rational), intent(in) :: a, b ! left + right

[ 21] type (Rational) :: c

[ 22] c % num = a % num*b % den + a % den*b % num

[ 23] c % den = a % den*b % den

[ 24] call reduce (c) ; end function add Rational

[ 25]

[ 26] function convert (name) result (value) ! rational to real

[ 27] type (Rational), intent(in) :: name

[ 28] real :: value ! decimal form

[ 29] value = float(name % num)/name % den ; end function convert

[ 30]

[ 31] function copy Rational (name) result (new)

[ 32] type (Rational), intent(in) :: name

[ 33] type (Rational) :: new

[ 34] new % num = name % num

[ 35] new % den = name % den ; end function copy Rational

[ 36]

[ 37] subroutine delete Rational (name) ! deallocate allocated items

[ 38] type (Rational), intent(inout) :: name ! simply zero it here

[ 39] name = Rational (0, 1) ; end subroutine delete Rational

[ 40]

[ 41] subroutine equal Integer (new, I) ! overload =, with integer


[ 42] type (Rational), intent(out) :: new ! left side of operator

[ 43] integer, intent(in) :: I ! right side of operator

[ 44] new % num = I ; new % den = 1 ; end subroutine equal Integer

[ 45]

[ 46] recursive function gcd (j, k) result (g) ! Greatest Common Divisor

[ 47] integer, intent(in) :: j, k ! numerator, denominator

[ 48] integer :: g

[ 49] if ( k == 0 ) then ; g = j

[ 50] else ; g = gcd ( k, modulo(j,k) ) ! recursive call

[ 51] end if ; end function gcd

[ 52]

[ 53] function get Denominator (name) result (n) ! an access function

[ 54] type (Rational), intent(in) :: name

[ 55] integer :: n ! denominator

[ 56] n = name % den ; end function get Denominator

(Fig. 3.15, A Fairly Complete Rational Number Class (continued))


c 2001 J.E. Akin 45[ 57] function get Numerator (name) result (n) ! an access function

[ 58] type (Rational), intent(in) :: name

[ 59] integer :: n ! numerator

[ 60] n = name % num ; end function get Numerator

[ 61]

[ 62] subroutine invert (name) ! rational to rational inversion

[ 63] type (Rational), intent(inout) :: name

[ 64] integer :: temp

[ 65] temp = name % num

[ 66] name % num = name % den

[ 67] name % den = temp ; end subroutine invert

[ 68]
[ 69] function is equal to (a given, b given) result (t f)

[ 70] type (Rational), intent(in) :: a given, b given ! left == right

[ 71] type (Rational) :: a, b ! reduced copies

[ 72] logical :: t f

[ 73] a = copy Rational (a given) ; b = copy Rational (b given)

[ 74] call reduce(a) ; call reduce(b) ! reduced to lowest terms

[ 75] t f = (a%num == b%num) .and. (a%den == b%den) ; end function

[ 76]

[ 77] subroutine list(name) ! as a pretty print fraction

[ 78] type (Rational), intent(in) :: name

[ 79] print *, name % num, "/", name % den ; end subroutine list

[ 80]

[ 81] function make Rational (numerator, denominator) result (name)

[ 82] ! Optional Constructor for a rational type

[ 83] integer, optional, intent(in) :: numerator, denominator

[ 84] type (Rational) :: name

[ 85] name = Rational(0, 1) ! set defaults

[ 86] if ( present(numerator) ) name % num = numerator

[ 87] if ( present(denominator)) name % den = denominator

[ 88] if ( name % den == 0 ) name % den = 1 ! now simplify

[ 89] call reduce (name) ; end function make Rational

[ 90]

[ 91] function mult Rational (a, b) result (c) ! to overload *

[ 92] type (Rational), intent(in) :: a, b

[ 93] type (Rational) :: c

[ 94] c % num = a % num * b % num

[ 95] c % den = a % den * b % den


[ 96] call reduce (c) ; end function mult Rational

[ 97]

[ 98] function Rational (numerator, denominator) result (name)

[ 99] ! Public Constructor for a rational type

[100] integer, optional, intent(in) :: numerator, denominator

[101] type (Rational) :: name

[102] if ( denominator == 0 ) then ; name = Rational (numerator, 1)

[103] else ; name = Rational (numerator, denominator) ; end if

[104] end function Rational

[105]

[106] subroutine reduce (name) ! to simplest rational form

[107] type (Rational), intent(inout) :: name

[108] integer :: g ! greatest common divisor

[109] g = gcd (name % num, name % den)

[110] name % num = name % num/g

[111] name % den = name % den/g ; end subroutine reduce

[112] end module class Rational

Figure 3.15: A Fairly Complete Rational Number Class


c 2001 J.E. Akin 46[ 1] include ’class Rational.f90’

[ 2] program main

[ 3] use class Rational

[ 4] implicit none

[ 5] type (Rational) :: x, y, z

[ 6] ! ------- only if Rational is NOT private ----------

[ 7] ! x = Rational(22,7) ! intrinsic constructor if public components

[ 8]

[ 9] x = Rational (22,7) ! public constructor if private components

[10] write (*,’("public x = ")’,advance=’no’); call list(x)


[11] write (*,’("converted x = ", g9.4)’) convert(x)

[12] call invert(x)

[13] write (*,’("inverted 1/x = ")’,advance=’no’); call list(x)

[14]

[15] x = make Rational () ! default constructor

[16] write (*,’("made null x = ")’,advance=’no’); call list(x)

[17] y = 4 ! rational = integer overload

[18] write (*,’("integer y = ")’,advance=’no’); call list(y)

[19] z = make Rational (22,7) ! manual constructor

[20] write (*,’("made full z = ")’,advance=’no’); call list(z)

[21] ! Test Accessors

[22] write (*,’("top of z = ", g4.0)’) get numerator(z)

[23] write (*,’("bottom of z = ", g4.0)’) get denominator(z)

[24] ! Misc. Function Tests

[25] write (*,’("making x = 100/360, ")’,advance=’no’)

[26] x = make Rational (100,360)

[27] write (*,’("reduced x = ")’,advance=’no’); call list(x)

[28] write (*,’("copying x to y gives ")’,advance=’no’)

[29] y = copy Rational (x)

[30] write (*,’("a new y = ")’,advance=’no’); call list(y)

[31] ! Test Overloaded Operators

[32] write (*,’("z * x gives ")’,advance=’no’); call list(z*x) ! times

[33] write (*,’("z + x gives ")’,advance=’no’); call list(z+x) ! add

[34] y = z ! overloaded assignment

[35] write (*,’("y = z gives y as ")’,advance=’no’); call list(y)

[36] write (*,’("logic y == x gives ")’,advance=’no’); print *, y==x

[37] write (*,’("logic y == z gives ")’,advance=’no’); print *, y==z


[38] ! Destruct

[39] call delete Rational (y) ! actually only null it here

[40] write (*,’("deleting y gives y = ")’,advance=’no’); call list(y)

[41] end program main ! Running gives:

[42] ! public x = 22 / 7 ! converted x = 3.143

[43] ! inverted 1/x = 7 / 22 ! made null x = 0 / 1

[44] ! integer y = 4 / 1 ! made full z = 22 / 7

[45] ! top of z = 22 ! bottom of z = 7

[46] ! making x = 100/360, reduced x = 5 / 18

[47] ! copying x to y gives a new y = 5 / 18

[48] ! z * x gives 55 / 63 ! z + x gives 431 / 126

[49] ! y = z gives y as 22 / 7 ! logic y == x gives F

[50] ! logic y == z gives T ! deleting y gives y = 0 / 1

Figure 3.16: Testing the Rational Number Class


c 2001 J.E. Akin 473.5 Exercises

1. Use the class Circle to create a class Sphere that computes the volume of a sphere. Have

a method that accepts an argument of a Circle. Use the radius of the Circle via a new member

get Circle radius to be added to the class Circle.

2. Use the class Circle and class Rectangle to create a class Cylinder that computes

the volume of a right circular cylinder. Have a method that accepts arguments of a Circle and a
height,

and a second method that accepts arguments of a Rectangle and a radius. In the latter member

use the height of the Rectangle via a new member get Rectangle height to be added to the

class Rectangle.

3. Create a vector class to treat vectors with an arbitrary number of real coefficients. Assume that
the

class Vector is defined as follows:

Vector Class

size
assign

integer

Vector

Vector make_Vector

Vector add_Real_to_Vector

Vector add_Vector

real, pointer data (:)

Vector copy_Vector

logical is_equal_to

Vector Vector

real values

Vector normalize_Vector

Vector list

Vector delete_Vector

real dot_Vector

Vector equal_Real

real length

integer size_Vector

Vector subtract_Real

Vector real_mult_Vector

Vector read_Vector

Vector subtract_Vector

Vector Vector_mult_real

Vector Vector_

real Vector_max_value

real Vector_min_value

Overload the common operators of (+) with add Vector and add Real to Vector, (–) with
subtract Vector and subtract Real, (*) with dot Vector, real mult Vector and Vector mult real, (=) with
equal Real to set all coefficients to a single real number, and (==) with

routine is equal to.

Include two constructors assign and make Vector. Let assign convert a real array into an instance

of a Vector. Provide a destructor, means to read and write a Vector, normalize a Vector, and
determine its

extreme values.
c 2001 J.E. Akin 484. Modify the above Vector class to extend it to a Sparse Vector Class where the
vast majority

of the coefficients are zero. Store and operate only on the non-zero entries.

Sparse_Vector Class

integer non_zeros

Sparse_Vector make_Sparse_Vector

Sparse_Vector add_Real_to_Sparse_Vector

Sparse_Vector add_Sparse_Vector

real, pointer values (:)

el_by_el_Mult

Sparse_Vector

logical is_equal_to

Sparse_Vector Sparse_Vector

Sparse_Vector show_r_v

normalize_Vector

integer largest_index

Sparse_Vector

delete_Sparse_Vector

real dot_Vector

Sparse_Vector equal_Vector

real length

integer rows_of
Sparse_Vector set_element

Sparse_Vector real_mult_Sparse

read_Vector

Sparse_Vector

Sparse_Vector show

Sparse_Vector Sparse_mult_real

integer size_of

Sparse_vector sub_Sparse_Vector

Sparse_Vector sum_Sparse_Vector

integer, pointer rows (:)

real get_element

real norm

normalize_Vector

Sparse_Vector pretty

Sparse_Vector

real Vector_max_value

real Vector_min_value

Sparse_Vector Vector_to_Sparse
What is Object Oriented Programming?

Now we move onto what might have been termed an advanced topic up until
about 10 years ago. Nowadays 'Object Oriented Programming has become the
norm. Languages like Java and Python embody the concept so much that you
can do very little without coming across objects somewhere. So what's it all
about?

The best introductions are, in my opinion:

 Object Oriented Analysis by Peter Coad & Ed Yourdon.


 Object Oriented Analysis and Design with Applications by Grady Booch (the
1st edition if you can find it)
 Object Oriented Software Construction by Bertrand Meyer (definitely the
2nd edition of this one)

These increase in depth, size and academic exactitude as you go down the list.
For most non professional programmers' purposes the first is adequate. For a
more programming focused intro try Object Oriented Programming by
Timothy Budd(2nd edition). This uses several languages to illustrate object
oriented programming techniques. It is much more strongly oriented towards
writing programs than any of the other books which cover the whole gamut of
theory and principle behind object orientation, at the design level as well as at
the code level. Finally for a whole heap of info on all topics OO try the Web
link site at: http://www.cetus-links.org

Assuming you don't have the time nor inclination to research all these books
and links right now, I'll give you a brief overview of the concept. (Note:Some
people find OO hard to grasp others 'get it' right away. Don't worry if you
come under the former category, you can still use objects even without really
'seeing the light'.)

One final point: it is possible to implement an Object Oriented design in a non


OO language through coding conventions, but it's usually an option of last
resort rather than a recommended strategy. If your problem fits well with OO
techniques then it's best to use an OO language. Most modern languages,
including Python, VBScript and JavaScript support OOP quite well. That
having been said I will be using Python throughout all the examples and only
showing the basic concepts in VBScript and JavaScript with little additional
explanation.

Data and Function - together

Objects are collections of data and functions that operate on that data. These
are bound together so that you can pass an object from one part of your
program and they automatically get access to not only the dataattributes but
the operations that are available too. This combining of data and function is
the very essence of Object Oriented Programming and is known
as encapsulation. (Some programming languages make the data invisible to
users of the object and thus require that the data be accessed via the object's
methods. This technique is properly known as data hiding, however in some
texts data hiding and encapsulation are used interchangeably.)

As an example of encapsulation, a string object would store the character


string but also provide methods to operate on that string - search, change case,
calculate length etc.

Objects use a message passing metaphor whereby one object passes a message


to another object and the receiving object responds by executing one of its
operations, a method. So a method is invoked on receipt of the corresponding
message by the owning object. There are various notations used to represent
this but the most common mimics the access to items in modules - a dot. Thus,
for a fictitious widget class:
w = Widget() # create new instance, w, of widget
w.paint() # send the message 'paint' to it

This would cause the paint method of the widget object to be invoked.

Defining Classes

Just as data has various types so objects can have different types. These
collections of objects with identical characteristics are collectively known as
a class. We can define classes and create instances of them, which are the
actual objects. We can store references to these objects in variables in our
programs.

Let's look at a concrete example to see if we can explain it better. We will


create a message class that contains a string - the message text - and a method
to print the message.
class Message:
def __init__(self, aString):
self.text = aString
def printIt(self):
print self.text

Note 1:One of the methods of this class is called __init__ and it is a special


method called a constructor. The reason for the name is that it is called when a
new object instance is created or constructed. Any variables assigned (and
hence created in Python) inside this method will be unique to the new
instance. There are a number of special methods like this in Python, nearly all
distinguished by the __xxx__ naming format. The exact timing of when a
constructor is called varies between languages, in Python init gets called after
the instance has actually been created in memory, in other languages the
constructor actually returms the instance itself. The difference is sufficiently
subtle that you don't usually need to worry about it.

Note 2:Both the methods defined have a first parameter self. The name is a
convention but it indicates the object instance. As we will soon see this
parameter is filled in by the interpreter at run-time, not by the programmer.
Thus printIt is called, on an instance of the class (see below), with no
arguments: m.printIt().

Note 3:We called the class Message with a capital 'M'. This is purely


convention, but it is fairly widely used, not just in Python but in other OO
languages too. A related convention says that method names should begin with
a lowercase letter and subsequent words in the name begin with uppercase
letters. Thus a method called "calculate current balance" would be
written: calculateCurrentBalance.

You may want to briefly revisit the 'Raw Materials' section and look again at
'user defined types'. The Python address example should be a little clearer
now. Essentially the only kind of user-defined type in Python is a class. A
class with attributes but no methods (except __init__ ) is effectively
equivalent to a construct called a record or struct in some programming
languages..

Using Classes

Having defined a class we can now create instances of our Message class and
manipulate them:
m1 = Message("Hello world")
m2 = Message("So long, it was short but sweet")

note = [m1, m2] # put the objects in a list


for msg in note:
msg.printIt() # print each message in turn

So in essence you just treat the class as if it was a standard Python data type,
which was after all the purpose of the excercise!

What is "self"?

No, it's not a philosophical debate, it's one of the questions most often asked
by new Python OOP programmers. Every method definition in a class in
Python starts with a parameter called self. The actual name selfis just a
convention, but like many programming conventions consistency is good so
let's stick with it! (As you'll see later JavaScript has a similar concept but uses
the name this instead.)

So what is self all about? Why do we need it?

Basically self is just a reference to the current instance. When you create an
instance of the class the instance contains its own data (as created by the
constructor) but not of the methods. Thus when we send a message to an
instance and it calls the corresponding method, it does so via an internal
reference to the class. It passes a reference to itself (self!) to the method so that
the class code knows which instance to use.

Let's look at a relatively familiar example. Consider a GUI application which


has lots of Button objects. When a user presses a button the method associated
with a button press is activated - but how does the Button method know which
of the buttons has been pressed? The answer is by referring to the self value
which will be a reference to the actual button instance that was pressed. We'll
see this in practice when we get to the GUI topic a little later.

So what happens when a message is sent to an object? It works like this:

 the client code calls the instance (sending the message in OOP speak).
 The instance calls the class method, passing a reference to itself (self).
 The class method then uses the passed reference to pick up the instance
data for the receiving object.

You can see this in action in this code sequence, notice that we can explicitly
call the class method, as we do in the last line:
>>> class C:
... def __init__(self, val): self.val = val
... def f(self): print "hello, my value is:", self.val
...
>>> # create two instances
>>> a = C(27)
>>> b = C(42)
>>> # first try sending messages to the instances
>>> a.f()
hello, my value is 27
>>> b.f()
hello, my value is 42
>>> # now call the method explicitly via the class
>>> C.f(a)
hello, my value is 27

So you see we can call the methods via the instance, in which case Python fills
in the self parameter for us, or explicitly via the class, in which case we need
to pass the self value explicitly.
Now you might be wondering why, if Python can provide the invisible
reference between the instance and its class can't Python also magically fill in
the self by itself? The answer is that Guido van Rossum designed it this way!
Many OOP languages do indeed hide the self parameter, but one of
the guiding principles of Python is that "explicit is better than implicit". You
soon get used to it and after a while not doing it seems strange.

Same thing, Different thing

What we have so far is the ability to define our own types (classes) and create
instances of these and assign them to variables. We can then pass messages to
these objects which trigger the methods we have defined. But there's one last
element to this OO stuff, and in many ways it's the most important aspect of
all.

If we have two objects of different classes but which support the same set of
messages but with their own corresponding methods then we can collect these
objects together and treat them identically in our program but the objects will
behave differently. This ability to behave differently to the same input
messages is known as polymorphism.

Typically this could be used to get a number of different graphics objects to


draw themselves on receipt of a 'paint' message. A circle draws a very
different shape from a triangle but provided they both have a paint method we,
as programmers, can ignore the difference and just think of them as 'shapes'.

Let's look at an example, where instead of drawing shapes we calculate their


areas:

First we create Square and Circle classes:


class Square:
def __init__(self, side):
self.side = side
def calculateArea(self):
return self.side**2

class Circle:
def __init__(self, radius):
self.radius = radius
def calculateArea(self):
import math
return math.pi*(self.radius**2)

Now we can create a list of shapes (either circles or squares) and then print out
their areas:
list = [Circle(5),Circle(7),Square(9),Circle(3),Square(12)]
for shape in list:
print "The area is: ", shape.calculateArea()

Now if we combine these ideas with modules we get a very powerful


mechanism for reusing code. Put the class definitions in a module - say
'shapes.py' and then simply import that module when we want to manipulate
shapes. This is exactly what has been done with many of the standard Python
modules, which is why accessing methods of an object looks a lot like using
functions in a module.

Inheritance

Inheritance is often used as a mechanism to implement polymorphism. Indeed


in many OO languages it is the only way to implement polymorphism. It
works as follows:

A class can inherit both attributes and operations from a parent or super class.


This means that a new class which is identical to another class in most respects
does not need to re-implement all the methods of the existing class, rather it
can inherit those capabilities and then override those that it wants to do
differently (like the calculateArea method in the case above)

Again an example might illustrate this best. We will use a class hierarchy of
bank accounts where we can deposit cash, obtain the balance and make a
withdrawal. Some of the accounts provide interest (which, for our purposes,
we'll assume is calculated on every deposit - an interesting innovation to the
banking world!) and others charge fees for withdrawals.

The BankAccount class

Let's see how that might look. First let's consider the attributes and operations
of a bank account at the most general (or abstract) level.

It's usually best to consider the operations first then provide attributes as
needed to support these operations. So for a bank account we can:

 Deposit cash,

 Withdraw cash,

 Check current balance and

 Transfer funds to another account.

To support these operations we will need a bank account ID (for the transfer
operation) and the current balance.
We can create a class to support that:
class BalanceError(Exception):
value = "Sorry you only have $%6.2f in your account"

class BankAccount:
def __init__(self, initialAmount):
self.balance = initialAmount
print "Account created with balance %5.2f" % self.balance

def deposit(self, amount):


self.balance = self.balance + amount

def withdraw(self, amount):


if self.balance >= amount:
self.balance = self.balance - amount
else:
raise BalanceError, BalanceError.value % self.balance

def checkBalance(self):
return self.balance

def transfer(self, amount, account):


try:
self.withdraw(amount)
account.deposit(amount)
except BalanceError:
print BalanceError.value

Note 1: We check the balance before withdrawing and also use an exception
to handle errors. Of course there is no Python error type BalanceError so we
needed to create one of our own - it's simply an subclass of the
standard Exception class with a string value. The string value is defined as an
attribute of the exception class purely as a convenience, it ensures that we can
generate standard error messages every time we raise an error. When we raise
BalanceError we pass the internal format string value filled in with the current
value of the object's balance. Notice that we didn't use self when defining the
value inBalanceError, that's because value is a shared attribute across all
instances, it is defined at the class level and known as a class variable. We
access it by using the class name followed by a dot: BalanceError.value as
seen above. Now, when the error generates its traceback it concludes by
printing out the formatted error string showing the current balance.

Note 2: The transfer method uses


the BankAccount's withdraw/deposit member functions or methods to do the
transfer. This is very common in OO and is known as self messaging. It means
that derived classes can implement their own versions of deposit/withdraw but
the transfer method can remain the same for all account types.
The InterestAccount class

Now we use inheritance to provide an account that adds interest (we'll assume
3%) on every deposit. It will be identical to the standard BankAccount class
except for the deposit method. So we simply override that:
class InterestAccount(BankAccount):
def deposit(self, amount):
BankAccount.deposit(self,amount)
self.balance = self.balance * 1.03

And that's it. We begin to see the power of OOP, all the other methods have
been inherited from BankAccount (by putting BankAccount inside the
parentheses after the new class name). Notice also that deposit called
the superclass's deposit method rather than copying the code. Now if we
modify the BankAccount deposit to include some kind of error checking
the sub-class will gain those changes automatically.

The ChargingAccount class

This account is again identical to a standard BankAccount class except that


this time it charges $3 for every withdrawal. As for the InterestAccount we can
create a class inheriting from BankAccount and modifying the withdraw
method.
class ChargingAccount(BankAccount):
def __init__(self, initialAmount):
BankAccount.__init__(self, initialAmount)
self.fee = 3

def withdraw(self, amount):


BankAccount.withdraw(self, amount+self.fee)

Note 1: We store the fee as an instance variable so that we can change it later
if necessary. Notice that we can call the inherited __init__ just like any other
method.

Note 2: We simply add the fee to the requested withdrawal and call the
BankAccount withdraw method to do the real work.

Note 3: We introduce a side effect here in that a charge is automatically levied
on transfers too, but that's probably what we want, so is OK.

Testing our system

To check that it all works try executing the following piece of code (either at
the Python prompt or by creating a separate test file).
from bankaccount import *

# First a standard BankAccount


a = BankAccount(500)
b = BankAccount(200)
a.withdraw(100)
# a.withdraw(1000)
a.transfer(100,b)
print "A = ", a.checkBalance()
print "B = ", b.checkBalance()

# Now an InterestAccount
c = InterestAccount(1000)
c.deposit(100)
print "C = ", c.checkBalance()

# Then a ChargingAccount
d = ChargingAccount(300)
d.deposit(200)
print "D = ", d.checkBalance()
d.withdraw(50)
print "D = ", d.checkBalance()
d.transfer(100,a)
print "A = ", a.checkBalance()
print "D = ", d.checkBalance()

# Finally transfer from charging account to the interest one


# The charging one should charge and the interest one add
# interest
print "C = ", c.checkBalance()
print "D = ", d.checkBalance()
d.transfer(20,c)
print "C = ", c.checkBalance()
print "D = ", d.checkBalance()

Now uncomment the line a.withdraw(1000) to see the exception at work.

That's it. A reasonably straightforward example but it shows how inheritance


can be used to quickly extend a basic framework with powerful new features.

We've seen how we can build up the example in stages and how we can put
together a test program to check it works. Our tests were not complete in that
we didn't cover every case and there are more checks we could have included -
like what to do if an account is created with a negative amount...

Collections of Objects

One problem that might have occurred to you is how we deal with lots of
objects. Or how to manage objects which we create at runtime. It's all very
well creating Bank Accounts statically as we did above:
acc1 = BankAccount(...)
acc2 = BankAccount(...)
acc3 = BankAccount(...)
etc...

But in the real world we don't know in advance how many accounts we need
to create. How do we deal with this? Lets consider the problem in more detail:

We need some kind of 'database' that allows us to find a given bank account
by its owners name (or more likely their bank account number - since one
person can have many accounts and several persons can have the same
name...)

Finding something in a collection given a unique key....hmmm, sounds like a


dictionary! Lets see how we'd use a Python dictionary to hold dynamically
created objects:
from bankaccount import *
import time

# Create new function to generate unique id numbers


def getNextID():
ok = raw_input("Create account[y/n]? ")
if ok[0] in 'yY': # check valid input
id = time.time() # use current time as basis of ID
id = int(id) % 10000 # convert to int and shorten to 4 digits
else: id = -1 # which will stop the loop
return id

# Let's create some accounts and store them in a dictionary


accountData = {} # new dictionary
while 1: # loop forever
id = getNextID()
if id == -1:
break # break forces an exit from the while loop
bal = float(raw_input("Opening Balance? ")) # convert string to
float
accountData[id] = BankAccount(bal) # use id to create new dictionary
entry
print "New account created, Number: %04d, Balance %0.2f" % (id,bal)

# Now let's access the accounts


for id in accountData.keys():
print "%04d\t%0.2f" % (id,accountData[id].checkBalance())

# and find a particular one


# Enter non-number to force exception and end program
while 1:
id = int(raw_input("Which account number? "))
if id in accountData.keys():
print "Balance = %0.2d" % accountData[id].checkBalance()
else: print "Invalid ID"

Of course the key you use for the dictionary can be anything that uniquely
identifies the object, it could be one of its attributes, like balance say (except
that balance would not be a very good unique key!). Anything at all that is
unique. You might find it worthwhile going back to the raw materials chapter
and reading the dictionary section again, they really are very useful containers.

Saving Your Objects

One snag with all of this is that you lose your data when the program ends.
You need some way of saving objects too. As you get more advanced you will
learn how to use databases to do that but we will look at using a simple text
file to save and retrieve objects. (If you are using Python there are a couple of
modules called Pickle and Shelve) that do this much more effectively but as
usual I'll try to show you the generic way to do it that will work in any
language. Incidentally the technical term for the ability to save and restore
objects is Persistence.

The generic way to do this is to create save and restore methods at the highest


level object and override in each class, such that they call the inherited version
and then add their locally defined attributes:
class A:
def __init__(self,x,y):
self.x = x
self.y = y

def save(self,fn):
f = open(fn,"w")
f.write(str(self.x)+ '\n') # convert to a string and add newline
f.write(str(self.y)+'\n')
return f # for child objects to use

def restore(self, fn):


f = open(fn)
self.x = int(f.readline()) # convert back to original type
self.y = int(f.readline())
return f

class B(A):
def __init__(self,x,y,z):
A.__init__(self,x,y)
self.z = z

def save(self,fn):
f = A.save(self,fn) # call parent save
f.write(str(self.z)+'\n')
return f # in case further children exist

def restore(self, fn):


f = A.restore(self,fn)
self.z = int(f.readline())
return f

# create instances
a = A(1,2)
b = B(3,4,5)

# save the instances


a.save('a.txt').close() # remember to close the file
b.save('b.txt').close()

# retrieve instances
newA = A(5,6)
newA.restore('a.txt').close() # remember to close the file
newB = B(7,8,9)
newB.restore('b.txt').close()
print "A: ",newA.x,newA.y
print "B: ",newB.x,newB.y,newB.z

Note: The values printed out are the restored values not the ones we used to
create the instances.

The key thing is to override the save/restore methods in each class and to call
the parent method as the first step. Then in the child class only deal with child
class attributes. Obviously how you turn an attribute into a string and save it is
up to you the programmer but it must be output on a single line. When
restoring you simply reverse the storing process.

Mixing Classes and Modules

Modules and classes both provide mechanisms for controlling the complexity
of a program. It seems reasonable that as programs get bigger we would want
to combine these features by putting classes into modules. Some authorities
recommend putting each class into a separate module but I find this simply
creates an explosion of modules and increases rather than decreases
complexity. Instead I group classes together and put the group into a module.
Thus in our example above I might put all the bank account class definitions in
one module, bankaccount, say, and then create a separate module for the
application code that uses the module. A simplified representation of that
would be:

# File: bankaccount.py
#
# Implements a set of bank account classes
###################

class BankAccount: ....

class InterestAccount: ...

class ChargingAccount: ...

And then to use it:


import bankaccount

newAccount = bankaccount.BankAccount(50)
newChrgAcct = bankaccount.ChargingAccount(200)
# now do stuff

But what happens when we have two classes in different modules that need to
access each others details? The simplest way is to import both modules, create
local instances of the classes we need and pass the instances of one class to the
other instances methods. Passing whole objects around is what makes it
object oriented programming. You don't need to extract the attributes out of
one object and pass them into another, just pass the entire object. Now if the
receiving object uses a polymorphic message to get at the information it needs
then the method will work with any kind of object that supports the message.

Let's make that more concrete by looking at an example. Let's create a short
module called logger that contains two classes. The first logs activity in a file.
This logger will have a single method log() which has a "loggable object" as a
parameter. The other class in our module is a Loggable class that can be
inherited by other classes to work with the logger. It looks like this:

# File: logger.py
#
# Create Loggable and Logger classes for logging activities
# of objects
############

class Loggable:
def activity(self):
return "This needs to be overridden locally"

class Logger:
def __init__(self, logfilename = "logger.dat"):
self._log = open(logfilename,"a")

def log(self, loggedObj):


self._log.write(loggedObj.activity() + '\n')

def __del__(self):
self._log.close()

Note that we have provided a destructor method (__del__) to close the file


when the logger object is deleted or garbage collected. This is another "magic
method" in Python (as shown by the double '_' characters) similar in many
ways to __init__()

Also notice that we've called the log attribute _log with a '_' character in front
of the name. This is another common naming convention in Python, like using
capitalized words for class names. A single underscore indicates that the
attribute is not intended to be accessed directly, but only via the methods of
the class.
Now before we can use our module we will create a new module which
defines loggable versions of our bank account classes:

# File: loggablebankaccount.py
#
# Extend Bank account classes to work with logger module.
###############################

import bankaccount, logger

class LoggableBankAccount(bankaccount.BankAccount, logger.Loggable):


def activity(self):
return "Account balance = %d" % self.checkBalance()

class LoggableInterestAccount(bankaccount.InterestAccount,
logger.Loggable):
def activity(self):
return "Account balance = %d" % self.checkBalance()

class LoggableChargingAccount(bankaccount.ChargingAccount,
logger.Loggable):
def activity(self):
return "Account balance = %d" % self.checkBalance()

Notice we are using a feature called multiple inheritance, where we inherit not


one but two parent classes. This isn't strictly needed in Python since we could
just have added an activity() method to our original classes and achieved the
same effect but in statically typed OOP languages such as Java or C++ this
technique would be necessary so I will show you the technique here for future
reference.

The sharp eyed amongst you may have noticed that the activity() method in
all three classes is identical. That means we could save ourselves some typing
by creating an intermediate type of loggable account class that inherits
Loggable and only has an activity method. We can then create our three
different loggable account types by inheriting from that new class as well as
from the vanilla Loggable class. Like this:
class LoggableAccount(logger.Loggable):
def activity(self):
return "Account balance = %d" % self.checkBalance()

class LoggableBankAccount(bankaccount.BankAccount, LoggableAccount):


pass

class LoggableInterestAccount(bankaccount.InterestAccount,
LoggableAccount):
pass

class LoggableChargingAccount(bankaccount.ChargingAccount,
LoggableAccount):
pass
It doesn't save a lot of code but it does mean we only have one method
definition to test and maintain instead of three identical methods. This type of
programming where we introduce a superclass with shared functionality is
sometimes called mixin programming and the minimal class is called a mixin
class. It is a common outcome of this style that the final class definitions have
little or no body but a long list of inherited classes, just as we see here. It's also
quite common that mixin classes do not themselves inherit from anything,
although in this case we did. In essence it's just a way of adding a common
method (or set of methods) to a class or set of classes via the power of
inheritance. (The term mixin originates in the world of ice cream parlours
where different flavours of ice cream are added (or mixed in) to vanilla to
produce a new flavour. The first language to support this style was called
Flavors which was a popular dialect of Lisp for a while.)

Now we come to the point of this excercise which is to show our application
code creating a logger object and some bank accounts and passing the
accounts to the logger, even though they are all defined in different modules!

# Test logging and loggable bank accounts.


#############

import logger
import loggablebankaccount as lba

log = logger.Logger()

ba = lba.LoggableBankAccount(100)
ba.deposit(700)
log.log(ba)

intacc = lba.LoggableInterestAccount(200)
intacc.deposit(500)
log.log(intacc)

Note the use of the as keyword to create a shortcut name when


importing loggablebankaccount

Note also that once we have created the local instances we no longer need to
use the module prefix and because there is no direct access from one object to
the other, it is all via messages, there is no need for the two class definition
modules to directly refer to each other either. Finally notice also that the
Logger works with instances of
both LoggableBankAccount and LoggableInterestAccount because they both
support theLoggable interface. Compatibility of object interfaces via
polymorphism is the foundation upon which all OOP programs are built.
I should point out that a much more sophisticated logging system is included
in the standard library logging module, this one was purely to demonstrate
some techniques. If you want logging facilities in your own programmes
investigate the standard logging module first of all.

Hopefully this has given you a taste of Object Oriented Programming and you
can move on to some of the other online tutorials, or read one of the books
mentioned at the beginning for more information and examples. Now we will
briefly look at how OOP is done in VBScript and JavaScript.

OOP in VBScript

VBScript supports the concept of objects and allows us to define classes and
create instances, however it does not support the concepts of inheritance or
polymorphism. VBScript is therefore what is known asObject Based rather
than fully Object Oriented. Nonetheless the concepts of combining data and
function in a single object remain useful, and a limited form of inheritance is
possible using a technique called delegation which we discuss below.

Defining classes

A class is defined in VBScript using the Class statement, like this:


<script type=text/VBScript>
Class MyClass
Private anAttribute
Public Sub aMethodWithNoReturnValue()
MsgBox "MyClass.aMethodWithNoReturnValue"
End Sub
Public Function aMethodWithReturnValue()
MsgBox "MyClass.aMethodWithReturnValue"
aMethodWithReturnValue = 42
End Function
End Class
</script>

This defines a new class called MyClass with an attribute


called anAttribute which is only visible to the methods inside the class, as
indicated by the keyword Private. It is conventional to declare data attributes
to be Private and most methods to be Public. This is known as data hiding
and has the advantage of allowing us to control access to the data by forcing
methods to be used and the methods can do data quality checks on the values
being passed in and out of the object. Python provides its own mechanism for
achieving this but it is beyond the scope of this tutorial.
Creating Instances

We create instances in VBScript with a combination of


the Set and New keywords. The variable to which the new instance is assigned
must also have been declared with the Dim keyword as is the usual VBScript
style.
<script type=text/VBScript>
Dim anInstance
Set anInstance = New MyClass
</script>

This creates an instance of the class declared in the previous section and
assigns it to the anInstance variable.

Sending Messages

Messages are sent to instances using the same dot notation used by Python.


<script type=text/VBScript>
Dim aValue
anInstance.aMethodWithNoReturnValue()
aValue = anInstance.aMethodWithReturnValue()
MsgBox "aValue = " & aValue
</script>

The two methods declared in the class definition are called, in the first case
there is no return value, in the second we assign the return to the
variable aValue. There is nothing unusual here apart from the fact that the
subroutine and function are preceded by the instance name.

Inheritance and Polymorphism

VBScript as a language does not provide any inheritance mechanism nor any
mechanism for polymorphism. However we can fake it to some degree by
using a technique called delegation. This simply means that we define an
attribute of the sub class to be an instance of the theoretical parent class. We
then define a method for all of the "inherited" methods which simply calls (or
delegates to), in turn, the method of the parent instance. Let's
subclass MyClass as defined above:
<script type=text/VBScript>
Class SubClass
Private parent
Private Sub Class_Initialize()
Set parent = New MyClass
End Sub
Public Sub aMethodWithNoReturnValue()
parent.aMethodWithNoREturnVAlue
End Sub
Public Function aMethodWithReturnValue()
aMethodWithReturnValue = parent.aMethodWithReturnValue
End Function
Public Sub aNewMethod
MsgBox "This is unique to the sub class"
End Sub
End Class

Dim inst,aValue
Set inst = New SubClass
inst.aMethodWithNoReturnVAlue
aValue = inst.aMethodWithReturnValue
inst.aNewMethod
MsgBox "aValue = " & CStr(aValue)
</script>

The key points to note here are the use of the private attribute parent and the
special, private method Class_Initialise. The former is the superclass
delegate attribute and the latter is the equivalent of Pythons __init__ method
for initializing instances when they are created, it is the VBScript constructor
in other words.

OOP in JavaScript

JavaScript supports objects using a technique called prototyping. This means


that there is no explicit class construct in JavaScript and instead we can define
a class in terms of a set of functions or a dictionary like concept known as
an initializer.

Defining classes

The most common way to define a JavaScript "class" is to create a function


with the same name as the class, effectively this is the constructor, but is not
contained within any other construct. It looks like this:
<script type=text/JavaScript>
function MyClass(theAttribute)
{
this.anAttribute = theAttribute;
};
</script>

You might notice the keyword this which is used in the same way as


Python's self as a placeholder reference to the current instance.

We can add new attributes to the class later using the built
in prototype attribute like this:
<script type=text/JavaScript>
MyClass.prototype.newAttribute = null;
</script>

This defines a new attribute of MyClass called newAttribute.


Methods are added by defining a normal function then assigning the function
name to a new attribute with the name of the method. Normally the method
and function have the same name, but there is nothing to stop you calling the
methods something different, as illustrated below:
<script type=text/JavaScript>
function oneMethod(){
return this.anAttribute;
}
MyClass.prototype.getAttribute = oneMethod;
function printIt(){
document.write(this.anAttribute + "<BR>");
};
MyClass.prototype.printIt = printIt;
</script>

Of course it would be more convenient to define the functions first then finish
up with the constructor and assign the methods inside the constructor and this
is in fact the normal approach, so that the full class definition looks like this:
<script type=text/JavaScript>
function oneMethod(){
return this.anAttribute;
};

function printIt(){
document.write(this.anAttribute + "<BR>");
};

function MyClass(theAttribute)
{
this.anAttribute = theAttribute;
this.getAttribute = oneMethod;
this.printIt = printIt;
};
</script>

Creating Instances

We create instances of classes using the keyword new, like this:


<script type=text/JavaScript>
var anInstance = new MyClass(42);
</script>

Which creates a new instance called anInstance.

Sending Messages

Sending messages in JavaScript is no different to our other languages, we use


the familiar dot notation.
<script type=text/JavaScript>
document.write("The attribute of anInstance is: <BR>");
anInstance.printIt();
</script>

Inheritance and Polymorphism

Unlike VBScript it is possible to use JavaScript's prototyping mechanism to


inherit from another class. It is rather more complex than the Python technique
but is not completely unmanageable, but it is, in my experience, a relatively
uncommon technique among JavaScript programmers.

The key to inheritance in JavaScript is the prototype keyword (we used it in


passing in the code above). By using prototype we can effectively add features
to an object after it has been defined. We can see this in action here:
<script type="text/javascript">
function Message(text){
this.text = text;
this.say = function(){
document.write(this.text + '<br>');
};
};

msg1 = new Message('This is the first');


msg1.say();

Message.prototype.shout = function(){
alert(this.text);
};

msg2 = new Message('This gets the new feature');


msg2.shout();

/* But so did msg1...*/


msg1.shout();

</script>

Note 1: We added the new alert method using prototype after creating


instance msg1 of the class but the feature was available to the existing instance
as well as to the instance, msg2 created after the addition. That is, the new
feature gets added to all instances of Message both existing and new.

Note 2: We used function in a new way here. It effectively is used to create a
function object which is assigned to the object property. That is:
obj.func = function(){...};

is equivalent to saying:
function f(){....};
obj.func = f;
We will see a similar concept in Python when we get to the Functional
Programming topic.

This prototyping feature gives rise to the interesting capability to change the
behavior of built-in JavaScript objects, either adding new features or changing
the way existing features function! Use this capability with great care if you
don't want to spend your time grappling with really confusing bugs.

This use of prototype as a mechanism for adding functionality to existing


classes has the disadvantage that it alters the existing instance behaviors and
changes the original class definition.

More conventional style inheritance is available too, as shown below:


<script type="text/javascript">
function Parent(){
this.name = 'Parent';
this.basemethod = function(){
alert('This is the parent');
};
};

function Child(){
this.parent = Parent;
this.parent();
this.submethod = function(){
alert('This from the child');
};
};

var aParent = new Parent();


var aChild = new Child();

aParent.basemethod();
aChild.submethod();
aChild.basemethod();

</script>

The key point to note here is that the Child object has access to


the basemethod without it being explicitly granted, it has inherited it from the
parent class by virtue of the assignment/call pair of lines:
this.parent = Parent;
this.parent();

within the Child class definition. And thus we have inherited


the basemethod from the Parent class!

We can, of course, use the same delegation trick we used with VBScript. Here
is the VBScript example translated into JavaScript:
<script type=text/JavaScript>
function noReturn(){
this.parent.printIt();
};

function returnValue(){
return this.parent.getAttribute();
};

function newMethod(){
document.write("This is unique to the sub class<BR>");
};

function SubClass(){
this.parent = new MyClass(27);
this.aMethodWithNoReturnValue = noReturn;
this.aMethodWithReturnValue = returnValue;
this.aNewMethod = newMethod;
};

var inst, aValue;


inst = new SubClass(); // define superclass
document.write("The sub class value is:<BR>");
inst.aMethodWithNoReturnValue();
aValue = inst.aMethodWithReturnValue();
inst.aNewMethod();
document.write("aValue = " + aValue);
</script>

We will see classes and objects being used in the following topics and case
studies. It is not always obvious to a beginner how this, apparently complex,
construct can make programs easier to write and understand but hopefully as
you see classes being used in real programs it will become clearer. One thing I
would like to say is that, for very small programs they do not really help and
almost certainly will make the program longer. However as your programs
start to get bigger - over about 100 lines say - then you will find that classes
and objects can help to keep things organized and even reduce the amount of
code you write.

If you are one of those who finds the whole OOP concept confusing don't
panic, many people have programmed for their whole lives without ever
creating a single class! On the other hand, if you can get to grips with objects
it does open up some powerful new techniques.
 UML Diagram for Checking Account Class

This class is designed to illustrate the concept of encapsulation. This class encapsulates both the data
(attributes) and methods (behaviors). Encapsulation is a fundamental concept of object-oriented design—all
objects contain both attributes and behavior. The UML class diagram is composed of only three parts: the class
name, the attributes, and the behaviors. This class diagram maps directly to the code in Listing 1.

class CheckingAccount {
private double balance = 0;
public void setBalance(double bal) {
balance = bal;
};
public double getBalance(){
return balance;
};
}

Listing 1: CheckingAccount.java

This direct mapping from class diagram to code (and back) is another important issue when designing classes.
This mapping not only helps with the design of the class, but also with the maintenance of the class. Multiple
class diagrams are used to design an object-oriented system and make up what is termed an object model.
Object models will be discussed at length in later articles.

Once a system is complete, the documentation pertaining to the design is obviously very important. The
deployment of a new application marks the beginning of the maintenance phase, which will continue for the
lifetime of the application and contain many, many bug fixes, updates, and enhancements to the system. While
the object-model is a great design tool, it is also a great maintenance tool.

However, as with all documentation, an object model that is not updated as the application changes is at best
useless, and at worst misleading. Anyone who has used flowcharts knows exactly what the problem is. For
example, consider an application that is deployed with flow charts included in the final documentation. If a bug is
identified and fixed in the code, unless the change in logic is retrofitted to the flow chart, the flow chart is out of
date and does not represent the current application. In the future, when another programmer, or perhaps even
the original programmer, revisits the documentation, it can be misleading. This may lead to a major problem. The
same problem can occur when classes change and the class diagram is not updated properly to reflect the
changes.

Why have we taken this interlude about updating documentation at this point? Because there now are tools to
manage much of the documentation process and I believe that anyone wanting to learn object-oriented design
must integrate the knowledge of these tools into their thought process as early as possible. In short, the process
of creating class diagrams and mapping them directly to code (and back) is tracked, and somewhat controlled, by
software tools. In future articles, we will get into much more detail about the tools themselves. Right now, just be
aware that the class diagrams and the code are tightly coupled.

Note: Some of the products that can help with the process are Rational Rose, owned by IBM and Visio, owned by
Microsoft.
Data Hiding
Returning to the actual CheckingAccount example, we can see that while the class contains both attributes and
behavior, not all of the class is accessible to other class. For example, consider again the balance attribute. Note
that balance is defined as private.

private double balance = 0;


We proved in the last article that attempting to access this attribute directly from an application would produce an
error. The application that produces this error is shown in Listing 2.

class Encapsulation {

public static void main(String args[]) {


System.out.println("Starting myEncapsulation...");
CheckingAccount myAccount = new CheckingAccount();
myAccount.balance = 40.00;
System.out.println("Balance = " + myAccount.getBalance());
}

}
Features of Object oriented Programming
The Objects Oriented programming language supports all the features of normal
programming languages. In addition it supports some important concepts and
terminology which has made it popular among programming methodology. 

The important features of Object Oriented programming are:

 Inheritance
 Polymorphism
 Data Hiding
 Encapsulation
 Overloading
 Reusability

Let us see a brief overview of these important features of Object Oriented programming

But before that it is important to know some new terminologies used in Object Oriented
programming namely

 Objects
 Classes

Objects:
In other words object is an instance of a class.

Classes:
These contain data and functions bundled together under a unit. In other words class is
a collection of similar objects. When we define a class it just creates template or Skelton.
So no memory is created when class is created. Memory is occupied only by object.

Example:

    Class classname
    {
        Data 
        Functions
    };
    main ( )
    {
        classname objectname1,objectname2,..;
    }

In other words classes acts as data types for objects.


Member functions:
The functions defined inside the class as above are called member functions.
Here the concept of Data Hiding figures

Data Hiding:
This concept is the main heart of an Object oriented programming. The data is hidden
inside the class by declaring it as private inside the class. When data or functions are
defined as private it can be accessed only by the class in which it is defined. When data
or functions are defined as public then it can be accessed anywhere outside the class.
Object Oriented programming gives importance to protecting data which in any system.
This is done by declaring data as private and making it accessible only to the class in
which it is defined. This concept is called data hiding. But one can keep member
functions as public.

So above class structure becomes

Example:

    Class classname


    {
        private: 
        datatype data;
    
        public:
        Member functions
    };
    main ( )
    {
        classname objectname1,objectname2,..;
    }

Encapsulation:
The technical term for combining data and functions together as a bundle is
encapsulation.

Inheritance:
Inheritance as the name suggests is the concept of inheriting or deriving properties of an
exiting class to get new class or classes. In other words we may have common features
or characteristics that may be needed by number of classes. So those features can be
placed in a common tree class called base class and the other classes which have these
charaterisics can take the tree class and define only the new things that they have on
their own in their classes. These classes are called derived class. The main advantage of
using this concept of inheritance in Object oriented programming is it helps in reducing
the code size since the common characteristic is placed separately called as base class
and it is just referred in the derived class. This provide the users the important usage of
terminology called as reusability
Reusability:
This usage is achieved by the above explained terminology called as inheritance.
Reusability is nothing but re- usage of structure without changing the existing one but
adding new features or characteristics to it. It is very much needed for any programmers
in different situations. Reusability gives the following advantages to users

It helps in reducing the code size since classes can be just derived from existing one and
one need to add only the new features and it helps users to save their time.

For instance if there is a class defined to draw different graphical figures say there is a
user who want to draw graphical figure and also add the features of adding color to the
graphical figure. In this scenario instead of defining a class to draw a graphical figure
and coloring it what the user can do is make use of the existing class for drawing
graphical figure by deriving the class and add new feature to the derived class namely
add the feature of adding colors to the graphical figure.

Polymorphism and Overloading:


Poly refers many. So Polymorphism as the name suggests is a certain item appearing in
different forms or ways. That is making a function or operator to act in different forms
depending on the place they are present is called Polymorphism. Overloading is a kind of
polymorphism. In other words say for instance we know that +, - operate on integer
data type and is used to perform arithmetic additions and subtractions. But operator
overloading is one in which we define new operations to these operators and make them
operate on different data types in other words overloading the existing functionality with
new one. This is a very important feature of object oriented programming methodology
which extended the handling of data type and operations.

You might also like