Object Oriented Programming
Samuel L. Marateck

Defining an object
Let's begin by defining an object through its form and then showing how it is used. The form of the object's definition in a program is like a record but instead of the components being just data fields, they can also be procedures and functions. Another obvious difference is that the word record is replaced by object. Let's examine the following object used in the object oriented version of the program for the Game of Life that appears on the homepage as LifeADT.pas. The object grid_type

 grid_type = object
     procedure zero;
     function isZero:boolean;
     procedure readit;
     procedure print;
     procedure generate;
     
     private
            grid:matrix;
 end {object grid_type};
appears in the INTERFACE section of a unit as a type definition (just as a record definition would appear in a program) and is the definition of an object (where matrix is defined earlier). The identifier for the object type is grid_type. The procedures and functions are called the methods of the object. Grid is called a field and since its declared private, it can only be used by the methods of the object. Ordinarily, the fields must come at the beginning of the object's definition; but here, since its private, it comes at the end. Also note that even the last item in the object, grid : matrix; must end with a semicolon.

Only the headings of the methods are written in the object's definition, the methods themselves follow the end of the object's definition in the IMPLEMENTATION section, for instance,

 procedure grid_type.zero;
 { Places blanks in the array}
 begin
      zero_em( grid )
 end;
The name of the method, here zero, must be preceded by the object type name and a period. Thus, the procedure heading is written as procedure grid_type.zero. The field members of the object (here, only grid is a field) are implicitly global to all the methods decared in the interface section of the object. Thus we can't declare grid within a method nor use it as the parameter of the method. So for instance, writing

 
procedure grid_type.zero( var grid : matrix )
would cause a compilation error.

The reason we call zero_em is to enable other methods (here, method generate) to zero matrices besides grid. Note that zero_em is not declared in the interface section of the object. Therefore, we can use grid as a parameter. Also, since zero_em is not declared in the interface section, it is private and cannot be used by the client. The dummy parameter in zero_em can be any identifier including grid.

 procedure zero_em( var new_grid : matrix );
 { enables other methods to zero matrices besides grid}
 var row: row_type;
    column: column_type;
 begin
     for row:= 0 to row_max + 1 do
         for column:= 0 to column_max + 1 do
             new_grid[row, column]:= blank
 end {zero_em};
 

If we had written zero as follows, it would only be able to zero grid.

procedure grid_type.zero;
 var row: row_type;
    column: column_type;
 begin
     for row:= 0 to row_max + 1 do
         for column:= 0 to column_max + 1 do
             grid[row, column]:= blank
 end {zero};
 

When writing a function that is declared in the INTERFACE section, e.g., isZero, you canot use the object name in the body of the function in the IMPLEMANTATION to precede the methid name. For instance writing grid_type.isZero:= true causes a recursive call and leads to an error. Write it as isZero:= true instead.

If a method, e.g., function neighbor, is not declared in the interface, the fields of the object are not global to it. So, in order to use grid in neighbor, it must be passed to it as a parameter:

procedure grid_type.generate;
{generates a new generation}
var j:row_type;
    k:column_type;
    new_grid:matrix;
begin
     zero_em( new_grid );
     for j:= 1 to row_max do
         for k:= 1 to column_max do begin
             if (grid[j,k] ='X') and (neighbor(grid, j,k) in [2, 3]) then
                new_grid[j, k]:= 'X';
             if (grid[j,k] = blank) and (neighbor(grid, j,k) = 3) then
                new_grid[j, k]:= 'X'
        end {for k};
     grid:=new_grid;
end;

If you want to use a method declared in the interface in the implementation of a method, you may omit the grid_type. part. So to use print in method generate, just write print. You do not have to write grid_type.print. If a method has parameters, once the method has been declared in the INTERFACE section with the parameters, the parameters may be omitted in the method heading in the IMPLEMENTATION section.

Using objects in a program is similar to using a record defined in a Type definition. To refer to the object, first declare a variable to be the object's type -- thus here, insert board:grid_type; in the var declaration of the main program. The variable board is called an instance of the object. To access method zero in the main program for instance, write board.zero. The method zero is said to be sending a message to the object instance board. One of the tenets of object oriented programming is that it is considered bad programming form for the user of the object to operate on the data of the object directly, as in, for instance explicitly using board.grid in the main program. Only the methods of the object should operate on the object's data field. The fact that the methods and data are combined in one object and that only the methods of the object operate on the data is called encapsulation. Once encapsulation is used, we don't have to worry about the datails or how the data is handled by the methods when we write the part of the program that uses the object. For instance, board.generate generates the next generation. We have used PRIVATE to enforce data encapsulation since any attempt to use board.grid will cause a compilation error.

Units in Turbo Pascal
Let's see how to save the compiled version (that is the binary code version) of an object so that it can be used by an activating program or another object. You do this by placing the object in what is called a unit.

A unit consists of an interface and implementation sections, and an optional initialization section. It starts with the keyword unit followed by the identifier that is the unit's name. For instance, the unit shown in LifeADT.pas starts with UNIT LifeADT. As with the standard units, a unit we write is activated by a USES statement in a program or another unit. The program that activates the unit is called the client. As opposed to the program name that appears in the program header and is not used by any part of the program, the unit name will be used when the client program calls on the unit. It must be the same as the DOS name used to save the program. Thus because of UNIT LifeADT, the unit must have the DOS name LifeADT.pas (and when compiled to disk, it will be saved as LifeADT.tpu). If the DOS name and UNIT name are not identical, a compilation error will occur during the client program compilation..

Abstract Data Type
The program for the Game of Life can be implemented with data structures other than an array. The interface of the unit is set up so that we don't have to care how the different operations are implemented. If we change the implementation so that the operations are done differently but still correctly, the client program that uses the object will give the same results. In other words the concept can be abstracted from the data structure. Hence, objects like LifeADT are called abstract data types.

THE INTERFACE SECTION
This section consists of definitions ( const, type and, var) that can be used by the client and also by the subprograms in the unit itself. It starts with the keyword interface and and ends with the appearance of the implementation section. It immediately follows the first line of the unit. (If the unit has a USES statement, the interface statement immedaitely follows it.)

 
 INTERFACE
 const row_max = 20; column_max = 75;
      blank = ' ';
 type matrix = array[0..21, 0..76] of char;
     row_type = 0..21;
     column_type = 0..76;
     grid_type = object
         procedure zero;
         function isZero:boolean;
         procedure readit;
         procedure print;
         procedure generate;
         private
            grid:matrix;
     end {object grid_type};

THE IMPLEMENTATION SECTION
The implementation section starts with the keyword implementation and ends with an end followed by a period. It follows the INTERFACE section and contains the subprograms themselves. This section can also contain the methods that can be used only by the subprograms in the unit. Remember that the last subprogram must, as always, end with a semicolon.

THE PRIVATE DECLARATION
As we have seen, in order to enforce encapsulation you can make fields of the object defined in an unit inaccessible to the client. Do this by placing the fields after the word private in the interface section.

COMPILING UNITS
To compile a unit, select the Compile menu bar and make sure that the Destination option is set to Memory. If it isn't, hit D .Then select the Compile menu aagain and choose the Compile option. If the compliation is successful, select the Compile menu bar again; but this time select Destination, thereby seting the option to Disk. Then select the Compile option. The computer will save the binary version of your unit on the disk using the first 8 letters of the unit name, here LifeADT, for the DOS name and TPU (Turbo Program Unit) for the extension. Thus our unit will be saved as LifeADT.tpu. After a unit has been compiled to the disk, you can use it in a program,

THE INITIALIZATION SECTION
If you want, you may include an initialization section in the implementation section. This is placed before the final end in the unit, and after a begin that you insert after the last subprogram. In this section you include those statements that initialize various items in the client. For instance, you could place all the assign statements there. The first thing the computer does when you run the client program is to execute the initialization sections of all the units. If you use more than one unit, the order you list them in the uses statement determines the order their initialization sections will be executed. \

Click house to return to Class home page.