Start Programming Using Object Pascal by Motaz Abdel Azeem - HTML preview

PLEASE NOTE: This is an HTML preview only and some elements such as links or page numbers may be incorrect.
Download the book in PDF, ePub, Kindle for a complete version.

Chapter Tw

r T o

Structured Programming

Introduction

Structured programming appeared after the expansion of programs. Large applications become unreadable and unmaintainable when they use unstructured code in one file.

In structured programming, we can split an application's source code into smaller pieces, called procedures and functions, and a we can also combine the procedures and functions that relate to one subject in a separate code file called a unit.

Structured programming benefits:

1. Partitioning an application's code to readable modules and procedures.

2. Code reusability: procedures and functions can be called from any part of the code many times without the need to rewrite and duplicate code.

3. Programmers could share and participate in one project at the same time. Each programmer could write their own procedures and functions in a separate unit, then they can integrate these units in the project.

4. Application maintenance and enhancement becomes easy: we can find bugs easily in procedures, also it is easy to improve procedures and functions, write new ones, add new units, etc.

5. Introducing modules and layers: we can divide an application into different logical layers and modules: for example we can write a unit that contains procedures that read/write data from/into files, and another unit that represent rules and validation layer, and a third one as a user interface layer.

Procedures

We have already used some procedures in the previous chapter, like Writeln, Readln, Reset, etc, but this time we need to write our own procedures that can be used by our applications.

In the next example we have written two procedures: SayHello and SayGoodbye: program Structured;

{$mode objfpc}{$H+}

uses

{$IFDEF UNIX}{$IFDEF UseCThreads}

cthreads,

{$ENDIF}{$ENDIF}

Classes

{ you can add units after this };

procedure SayHello;

begin

Writeln('Hello there');

end;

procedure SayGoodbye;

begin

Writeln('Good bye');

end;

begin // Here main application starts

Writeln('This is the main application started');

SayHello;

Writeln('This is structured application');

SayGoodbye;

Write('Press enter key to close');

Readln;

end.

We see that the procedure looks like a small program, with its own begin. .end, and it can be called from the main application's code.

Parameters

In the next example, we introduce parameters, which are variables passed to a procedure when calling it:

procedure WriteSumm(x, y: Integer);

begin

Writeln('The summation of ', x, ' + ', y, ' = ', x + y)

end;

begin

WriteSumm(2, 7);

Write('Press enter key to close');

Readln;

end.

In the main application, we have called the WriteSumm procedure and passed the values 2, 7 to it, and the procedure will receive them in x, y integer variables to write the summation result of them.

In the next example, we have rewritten the restaurant application using procedures: Restaurant program using procedures

procedure Menu;

begin

Writeln('Welcome to Pascal Restaurant. Please select your order');

Writeln('1 - Chicken (10$)');

Writeln('2 - Fish (7$)');

Writeln('3 - Meat (8$)');

Writeln('4 – Salad (2$)');

Writeln('5 - Orange Juice (1$)');

Writeln('6 - Milk (1$)');

Writeln;

end;

procedure GetOrder(AName: string; Minutes: Integer);

begin

Writeln('You have ordered : ', AName, ', this will take ',

Minutes, ' minutes');

end;

// Main application

var

Meal: Byte;

begin

Menu;

Write('Please enter your selection: ');

Readln(Meal);

case Meal of

1: GetOrder('Chicken', 15);

2: GetOrder('Fish', 12);

3: GetOrder('Meat', 18);

4: GetOrder('Salad', 5);

5: GetOrder('Orange juice', 2);

6: GetOrder('Milk', 1);

else

Writeln('Wrong entry');

end;

Write('Press enter key to close');

Readln;

end.

Now the main application becomes smaller and more readable. The details of the other parts are separated in procedures, like the get order and display menu procedures.

Functions

Functions are similar to procedures, but have an additional feature, which is returning a value. We have used functions before, like UpperCase, which converts and returns text to upper case, and Abs, which returns the absolute value of a number.

In the next example, we have written the GetSumm function, which receives two integer values and returns their summation:

function GetSumm(x, y: Integer): Integer;

begin

Result:= x + y;

end;

var

Sum: Integer;

begin

Sum:= GetSumm(2, 7);

Writeln('Summation of 2 + 7 = ', Sum);

Write('Press enter key to close');

Readln;

end.

Notice that we have declared the function as Integer, and we have used the Result keyword to represent the function's return value.

In the main application, we have used the variable Sum, in which we receive the function result, but we could eliminate this intermediate variable and call this function inside the Writeln procedure. This is one difference between functions and procedures. We can call functions as input parameters in other procedures or functions, but we can not call procedures as parameters of other functions and procedures:

function GetSumm(x, y: Integer): Integer;

begin

Result:= x + y;

end;

begin

Writeln('Summation of 2 + 7 = ', GetSumm(2, 7));

Write('Press enter key to close');

Readln;

end.

In the next example, we have rewritten the Restaurant program using functions: Restaurant program using functions

procedure Menu;

begin

Writeln('Welcome to Pascal Restaurant. Please select your order');

Writeln('1 - Chicken (10$)');

Writeln('2 - Fish (7$)');

Writeln('3 - Meat (8$)');

Writeln('4 – Salad (2$)');

Writeln('5 - Orange Juice (1$)');

Writeln('6 - Milk (1$)');

Writeln('X - nothing');

Writeln;

end;

function GetOrder(AName: string; Minutes, Price: Integer): Integer; begin

Writeln('You have ordered: ', AName, ' this will take ',

Minutes, ' minutes');

Result:= Price;

end;

var

Selection: Char;

Price: Integer;

Total: Integer;

begin

Total:= 0;

repeat

Menu;

Write('Please enter your selection: ');

Readln(Selection);

case Selection of

'1': Price:= GetOrder('Checken', 15, 10);

'2': Price:= GetOrder('Fish', 12, 7);

'3': Price:= GetOrder('Meat', 18, 8);

'4': Price:= GetOrder('Salad', 5, 2);

'5': Price:= GetOrder('Orange juice', 2, 1);

'6': Price:= GetOrder('Milk', 1, 1);

'x', 'X': Writeln('Thanks');

else

begin

Writeln('Wrong entry');

Price:= 0;

end;

end;

Total:= Total + Price;

until (Selection = 'x') or (Selection = 'X');

Writeln('Total price = ', Total);

Write('Press enter key to close');

Readln;

end.

Local Variables

We can define variables locally inside a procedure or function to be used only inside its code. These variables can not be accessed from the main application's code or from other procedures and functions.

Example:

procedure Loop(Counter: Integer);

var

i: Integer;

Sum: Integer;

begin

Sum:= 0;

for i:= 1 to Counter do

Sum:= Sum + i;

Writeln('Summation of ', Counter, ' numbers is: ', Sum);

end;

begin // Main program section

Loop;

Write('Press enter key to close');

Readln;

end.

In the procedure Loop, there are two local variables Sum and I. Local variables are stored in Stack memory, which is a part of memory that allocates variables temporarily until the procedure's execution is finished. That means it will be unaccessible and can be overwritten when program execution reaches this line of code:

Write('Press enter key to close');

Global variables can be accessed from the main program and other procedures and functions. They can hold values until the application is closed, but this can break the structure of the program and make it hard to trace errors, because any procedure can change global variable values, which may result in unknown values and misbehavior when we forget to initialize them.

Defining local variables guarantees their privacy, which helps the procedures and functions to be ported or called from anywhere without worry about global variables values.

News database application

In this example we have three procedures and one function: Add News title, display all News, searching, and displaying menu to let the user select the function that he/she want to execute: program news;

{$mode objfpc}{$H+}

uses

{$IFDEF UNIX}{$IFDEF UseCThreads}

cthreads,

{$ENDIF}{$ENDIF}

Classes, SysUtils

{ you can add units after this };

type

TNews = record

ATime: TDateTime;

Title: string[100];

end;

procedure AddTitle;

var

F: file of TNews;

News: TNews;

begin

AssignFile(F, 'news.dat');

Write('Input current news title: ');

Readln(News.Title);

News.ATime:= Now;

if FileExists('news.dat') then

begin

FileMode:= 2; // Read/Write

Reset(F);

Seek(F, System.FileSize(F)); // Go to last record to append

end

else

Rewrite(F);

Write(F, News);

CloseFile(F);

end;

procedure ReadAllNews;

var

F: file of TNews;

News: TNews;

begin

AssignFile(F, 'news.dat');

if FileExists('news.dat') then

begin

Reset(F);

while not Eof(F) do

begin

Read(F, News);

Writeln('------------------------------');

Writeln('Title: ', News.Title);

Writeln('Time : ', DateTimeToStr(News.ATime));

end;

CloseFile(F);

end

else

Writeln('Empty database');

end;

procedure Search;

var

F: file of TNews;

News: TNews;

Keyword: string;

Found: Boolean;

begin

AssignFile(F, 'news.dat');

Write('Input keyword to search for: ');

Readln(Keyword);

Found:= False;

if FileExists('news.dat') then

begin

Reset(F);

while not Eof(F) do

begin

Read(F, News);

if Pos(LowerCase(Keyword), LowerCase(News.Title)) > 0 then

begin

Found:= True;

Writeln('------------------------------');

Writeln('Title: ', News.Title);

Writeln('Time : ', DateTimeToStr(News.ATime));

end;

end;

CloseFile(F);

if not Found then

Writeln(Keyword, ' Not found');

end

else

Writeln('Empty database');

end;

function Menu: char;

begin

Writeln;

Writeln('...........News database..........');

Writeln('1. Add news title');

Writeln('2. Display all news');

Writeln('3. Search');

Writeln('x. Exit');

Write('Please input a selection : ');

Readln(Result);

end;

// Main application

var

Selection: Char;

begin

repeat

Selection:= Menu;

case Selection of

'1': AddTitle;

'2': ReadAllNews;

'3': Search;

end;

until LowerCase(Selection) = 'x';

end.

This application is easy to read and has compact and clear code in the main section. We can also add new features to any procedure without affecting or modifying other parts.

Functions as input parameters

As we said before, we can call the function as a procedure/function input parameter, because we can treat it as a value.

See the example below:

function DoubleNumber(x: Integer): Integer;

begin

Result:= x * 2;

end;

// Main

begin

Writeln('The double of 5 is : ', DoubleNumber(5));

Readln;

end.

Note that we have called the DoubleNumber function from inside the Writeln procedure.

In the next modification of the example, we will use an intermediate variable to store the function's result, and then use it as input to the Writeln procedure:

function DoubleNumber(x: Integer): Integer;

begin

Result:= x * 2;

end;

// Main

var

MyNum: Integer;

begin

MyNum:= DoubleNumber(5);

Writeln('The double of 5 is : ', MyNum);

Readln;

end.

We can also call functions within if conditions and loop conditions:

function DoubleNumber(x: Integer): Integer;

begin

Result:= x * 2;

end;

// Main

begin

if DoubleNumber(5) > 10 then

Writeln('This number is larger than 10')

else

Writeln('This number is equal or less than 10);

Readln;

end.

Procedure and function output parameters

In the previous usage of functions, we found that we can return only one value, which is the result of the function, but how can we return more than one value in functions or procedures?

Let us do this experiment:

procedure DoSomething(x: Integer);

begin

x:= x * 2;

Writeln('From inside procedure: x = ', x);

end;

// main

var

MyNumber: Integer;

begin

MyNumber:= 5;

DoSomething(MyNumber);

Writeln('From main program, MyNumber = ', MyNumber);

Writeln('Press enter key to close');

Readln;

end.

In this example, the doSomething procedure receives x as an Integer value, then it multiplies it by two, and then finally it displays it.

In the main part of the program, we declared the variable MyNumber as an Integer, put the number 5 in it, and then passed it as a parameter to the DoSomething procedure. In this case, the MyNumber value (5) will be copied into the x variable.

After calling the function, X 'svalue will be 10, but when we display MyNumber after procedure calling we will find that it still holds the value 5. That means MyNumber and X have two different locations in memory, which is normal.

This type of parameter passing is called calling by value, which does not affect the original parameter MyNumber. We also could use constants to pass such values, e.g:

DoSomething(5);

Calling by reference

If we add the var keyword to the declaration of DoSomething's x parameter, things will be different now:

procedure DoSomething(var x: Integer);

begin

x:= x * 2;

Writeln('From inside procedure: x = ', x);

end;

// main

var

MyNumber: Integer;

begin

MyNumber:= 5;

DoSomething(MyNumber);

Writeln('From main program, MyNumber = ', MyNumber);

Writeln('Press enter key to close');

Readln;

end.

This time MyNumber's value will be changed according to x, which means they are sharing the same memory location.

We should pass a variable (not a constant) to the procedure this time, using the same type: if the parameter is declared as Byte, then MyNumber should be declared as Byte; if it is Integer, then it should be Integer.

The next example will generate an error when calling DoSomething, which requires a variable for its parameter:

DoSomething(5);

In calling by value, the previous code could be used, because it cares only about having a value passed as its parameter, and 5 is a value, but in calling by reference the program cares about having a variable passed as its parameter and then acts on its value.

In the next example, we will pass two variables, and then the procedure will swap their values: procedure SwapNumbers(var x, y: Integer);

var

Temp: Integer;

begin

Temp:= x;

x:= y;

y:= Temp;

end;

// main

var

A, B: Integer;

begin

Write('Please input value for A: ');

Readln(A);

Write('Please input value for B: ');

Readln(B);

SwapNumbers(A, B);

Writeln('A = ', A, ', and B = ', B);

Writeln('Press enter key to close');

Readln;

end.

Units

A Unit in Pascal is a library that contains procedures, functions, constants, and user defined types that can be used in many applications.

Units are used to achieve these goals:

1. Accumulate procedures and functions that are frequently used in applications in external units.

This achieves code reusability in software development.

2. Combine procedures and functions that are used to perform certain tasks in one entity. Instead of populating the main application's source code with unrelated procedures, it is better to divide the application into logical modules using units.

To create a new unit, go to File/New Unit in the Lazarus menu, and Lazarus creates this template: unit Unit1;

{$mode objfpc}{$H+}

interface