Marco Web Center

[an error occurred while processing this directive]
Essential Pascal Cover

The cover of the 4th edition of Essential Pascal, the first available in print (and PDF) on Lulu.com.

Marco Cantù's
Essential Pascal

Chapter 5
Statements

If the data types are one of the foundations of Pascal programming the other are statements. Statements of the programming language are based on keywords and other elements which allow you to indicate to a program a sequence of operations to perform. Statements are often enclosed in procedures or functions, as we'll see in the next chapter. Now we'll just focus on the basic types of commands you can use to create a program.

Simple and Compound Statements

A Pascal statement is simple when it doesn't contain any other statements. Examples of simple statements are assignment statements and procedure calls. Simple statements are separated by a semicolon:

X := Y + Z;  // assignment
Randomize;   // procedure call
Usually, statements are part of a compound statement, marked by begin and end brackets. A compound statement can appear in place of a generic Pascal statement. Here is an example:
begin
  A := B;
  C := A * 2;
end;
The semicolon after the last statement before the end isn't required, as in the following:
begin
  A := B;
  C := A * 2
end;
Both versions are correct. The first version has a useless (but harmless) semicolon. This semicolon is, in fact, a null statement; that is, a statement with no code. Notice that, at times, null statements can be used inside loops or in other particular cases.

Note: Although these final semicolons serve no purpose, I tend to use them and suggest you do the same. Sometimes after you've written a couple of lines you might want to add one more statement. If the last semicolon is missing you should remember to add it, so it might be better to add it in the first place.

Assignment Statements

Assignments in Pascal use the colon-equal operator, an odd notation for programmers who are used to other languages. The = operator, which is used for assignments in some other languages, in Pascal is used to test for equality.

Note: By using different symbols for an assignment and an equality test, the Pascal compiler (like the C compiler) can translate source code faster, because it doesn't need to examine the context in which the operator is used to determine its meaning. The use of different operators also makes the code easier for people to read.

Conditional Statements

A conditional statement is used to execute either one of the statements it contains or none of them, depending on some test. There are two basic flavors of conditional statements: if statements and case statements.

If Statements

The if statement can be used to execute a statement only if a certain condition is met (if-then), or to choose between two different alternatives (if-then-else). The condition is described with a Boolean expression. A simple Delphi example will demonstrate how to write conditional statements. First create a new application, and put two check boxes and four buttons in the form. Do not change the names of buttons or check boxes, but double-click on each button to add a handler for its OnClick event. Here is a simple if statement for the first button:

procedure TForm1.Button1Click(Sender: TObject);
begin
  // simple if statement
  if CheckBox1.Checked then
    ShowMessage ('CheckBox1 is checked')
end;

When you click on the button, if the first check box has a check mark in it, the program will show a simple message (see Figure 5.1). I've used the ShowMessage function because it is the simplest Delphi function you can use to display a short message to the user.

Figure 5.1: The message displayed by the IfTest example when you press the first button and the first check box is checked.

If you click the button and nothing happens, it means the check box was not checked. In a case like this, it would probably be better to make this more explicit, as with the code for the second button, which uses an if-then-else statement:

procedure TForm1.Button2Click(Sender: TObject);
begin
  // if-then-else statement
  if CheckBox2.Checked then
    ShowMessage ('CheckBox2 is checked')
  else
    ShowMessage ('CheckBox2 is NOT checked');
end;

Notice that you cannot have a semicolon after the first statement and before the else keyword, or the compiler will issue a syntax error. The if-then-else statement, in fact, is a single statement, so you cannot place a semicolon in the middle of it.

An if statement can be quite complex. The condition can be turned into a series of conditions (using the and, or and not Boolean operators), or the if statement can nest a second if statement. The last two buttons of the IfTest example demonstrate these cases:

procedure TForm1.Button3Click(Sender: TObject);
begin
  // statement with a double condition
  if CheckBox1.Checked and CheckBox2.Checked then
    ShowMessage ('Both check boxes are checked')
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  // compound if statement
  if CheckBox1.Checked then
    if CheckBox2.Checked then
      ShowMessage ('CheckBox1 and 2 are checked')
    else
      ShowMessage ('Only CheckBox1 is checked')
  else
    ShowMessage (
      'Checkbox1 is not checked, who cares for Checkbox2?')
end;

Look at the code carefully and run the program to see if you understand everything. When you have doubts about a programming construct, writing a very simple program such as this can help you learn a lot. You can add more check boxes and increase the complexity of this small example, making any test you like.

Case Statements

If your if statements become very complex, at times you can replace them with case statements. A case statement consists in an expression used to select a value, a list of possible values, or a range of values. These values are constants, and they must be unique and of an ordinal type. Eventually, there can be an else statement that is executed if none of the labels correspond to the value of the selector. Here are two simple examples:

case Number of
  1: Text := 'One';
  2: Text := 'Two';
  3: Text := 'Three';
end;

case MyChar of
  '+' : Text := 'Plus sign';
  '-' : Text := 'Minus sign';
  '*', '/': Text := 'Multiplication or division';
  '0'..'9': Text := 'Number';
  'a'..'z': Text := 'Lowercase character';
  'A'..'Z': Text := 'Uppercase character';
else
  Text := 'Unknown character';
end;

Loops in Pascal

The Pascal language has the typical repetitive statements of most programming languages, including for, while, and repeat statements. Most of what these loops do will be familiar if you've used other programming languages, so I'll cover them only briefly.

The For Loop

The for loop in Pascal is strictly based on a counter, which can be either increased or decreased each time the loop is executed. Here is a simple example of a for loop used to add the first ten numbers.

var
  K, I: Integer;
begin
  K := 0;
  for I := 1 to 10 do
    K := K + I;

This same for statement could have been written using a reverse counter:

var
  K, I: Integer;
begin
  K := 0;
  for I := 10 downto 1 do
    K := K + I;

The for loop in Pascal is less flexible than in other languages (it is not possible to specify an increment different than one), but it is simple and easy to understand. If you want to test for a more complex condition, or to provide a customized counter, you need to use a while or repeat statement, instead of a for loop.

Note: The counter of a for loop doesn't need to be a number. It can be a value of any ordinal type, such as a character or an enumerated type.

While and Repeat Statements

The difference between the while-do loop and the repeat-until loop is that the code of the repeat statement is always executed at least once. You can easily understand why by looking at a simple example:

while (I <= 100) and (J <= 100) do
begin
  // use I and J to compute something...
  I := I + 1;
  J := J + 1;
end;

repeat
  // use I and J to compute something...
  I := I + 1;
  J := J + 1;
until (I > 100) or (J > 100);

If the initial value of I or J is greater than 100, the statements inside the repeat-until loop are executed once anyway.

The other key difference between these two loops is that the repeat-until loop has a reversed condition. The loop is executed as long as the condition is not met. When the condition is met, the loop terminates. This is the opposite from a while-do loop, which is executed while the condition is true. For this reason I had to reverse the condition in the code above to obtain a similar statement.

An Example of Loops

To explore the details of loops, let's look at a small Delphi example. The Loops program highlights the difference between a loop with a fixed counter and a loop with an almost random counter. Start with a new blank project, place a list box and two buttons on the main form, and give the buttons a proper name (BtnFor and BtnWhile) by setting their Name property in the Object Inspector. You can also remove the word Btn from the Caption property (and eventually even add the & character to it to activate the following letter as a shortcut key). Here is a summary of the textual description of this form:

object Form1: TForm1
  Caption = 'Loops'
  object ListBox1: TListBox ...
  object BtnFor: TButton
    Caption = '&For'
    OnClick = BtnForClick
  end
  object BtnWhile: TButton
    Caption = '&While'
    OnClick = BtnWhileClick
  end
end

Figure 5.2: Each time you press the For button of the Loops example, the list box is filled with consecutive numbers.

Now we can add some code to the OnClick events of the two buttons. The first button has a simple for loop to display a list of numbers, as you can see in Figure 5.2. Before executing this loop, which adds a number of strings to the Items property of the list box, you need to clear the contents of the list box itself:

procedure TForm1.BtnForClick(Sender: TObject);
var
  I: Integer;
begin
  ListBox1.Items.Clear;
  for I := 1 to 20 do
    Listbox1.Items.Add ('String ' + IntToStr (I));
end;

The code associated with the second button is slightly more complex. In this case, there is a while loop based on a counter, which is increased randomly. To accomplish this, I've called the Randomize procedure, which resets the random number generator, and the Random function with a range value of 100. The result of this function is a number between 0 and 99, chosen randomly. The series of random numbers control how many times the while loop is executed.

procedure TForm1.BtnWhileClick(Sender: TObject);
var
  I: Integer;
begin
  ListBox1.Items.Clear;
  Randomize;
  I := 0;
  while I < 1000 do
  begin
    I := I + Random (100);
    Listbox1.Items.Add ('Random Number: ' + IntToStr (I));
  end;
end;

Each time you click the While button, the numbers are different, because they depend on the random-number generator. Figure 5.3 shows the results from two separate button-clicks. Notice that not only are the generated numbers different each time, but so is the number of items. That is, this while loop is executed a random numbers of times. If you press the While button several times in a row, you'll see that the list box has a different number of lines.

Figure 5.3: The contents of the list box of the Loops example change each time you press the While button. Because the loop counter is incremented by a random value, every time you press the button the loop may execute a different number of times.

Note: You can alter the standard flow of a loop's execution using the Break and Continue system procedures. The first interrupts the loop; the second is used to jump directly to the loop test or counter increment, continuing with the next iteration of the loop (unless the condition is zero or the counter has reached its highest value). Two more system procedures, Exit and Halt, let you immediately return from the current function or procedure or terminate the program.

The With Statement

The last kind of Pascal statement I'll focus on is the with statement, which used to be peculiar to this programming language (although it has been recentrly introduced also in JavaScript and Visual Basic) and can be very useful in Delphi programming.

The with statement is nothing but shorthand. When you need to refer to a record type variable (or an object), instead of repeating its name every time, you can use a with statement. For example, while presenting the record type, I wrote this code:

type
  Date = record
    Year: Integer;
    Month: Byte;
    Day: Byte;
  end;

var
  BirthDay: Date;

begin
  BirthDay.Year := 1997;
  BirthDay.Month := 2;
  BirthDay.Day := 14;

Using a with statement, I can improve the final part of this code, as follows:

begin
  with BirthDay do
  begin
    Year := 1995;
    Month := 2;
    Day := 14;
  end;

This approach can be used in Delphi programs to refer to components and other class types. For example, we can rewrite the final part of the last example, Loops, using a with statement to access the items of the list box:

procedure TForm1.WhileButtonClick(Sender: TObject);
var
  I: Integer;
begin
  with ListBox1.Items do
  begin
    Clear; // shortcut
    Randomize;
    I := 0;
    while I < 1000 do
    begin
      I := I + Random (100);
      // shortcut:
      Add ('Random Number: ' + IntToStr (I));
    end;
  end;
end;

When you work with components or classes in general, the with statement allows you to skip writing some code, particularly for nested fields. For example, suppose that you need to change the Width and the Color of the drawing pen for a form. You can write the following code:

Form1.Canvas.Pen.Width := 2;
Form1.Canvas.Pen.Color := clRed;

But it is certainly easier to write this code:

with Form1.Canvas.Pen do
begin
  Width := 2;
  Color := clRed;
end;

When you are writing complex code, the with statement can be effective and spares you the declaration of some temporary variables, but it has a drawback. It can make the code less readable, particularly when you are working with different objects that have similar or corresponding properties.

A further drawback is that using the with statement can allow subtle logical errors in the code that the compiler will not detect. For example:

with Button1 do
begin
  Width := 200;
  Caption := 'New Caption';
  Color := clRed;
end;

This code changes the Caption and the Width of the button, but it affects the Color property of the form, not that of the button! The reason is that the TButton components don't have the Color property, and since the code is executed for a form object (we are writing a method of the form) this object is accessed by default. If we had instead written:

Button1.Width := 200;
Button1.Caption := 'New Caption';
Button1.Color := clRed; // error!

the compiler would have issued an error. In general, we can say that since the with statement introduces new identifiers in the current scope, we might hide existing identifiers, or wrongfully access another identifier in the same scope (as in the first version of this code fragment). Even considering this kind of drawback, I suggest you get used to with statements, because they can be really very handy, and at times even make the code more readable.

You should, however, avoid using multiple with statements, such as:

with ListBox1, Button1 do...

The code following this would probably be highly unreadable, because for each property defined in this block you would need to think about which component it refers to, depending on the respective properties and the order of the components in the with statement.

Note: Speaking of readability, Pascal has no endif or endcase statement. If an if statement has a begin-end block, then the end of the block marks the end of the statement. The case statement, instead, is always terminated by an end. All these end statements, often found one after the other, can make the code difficult to follow. Only by tracing the indentations can you see which statement a particular end refers to. A common way to solve this problem and make the code more readable is to add a comment after the end statement indicating its role, as in:

if ... then
 ...
end; // if

Conclusion

This chapter has described how to code conditional statements and loops. Instead of writing long lists of such statements, programs are usually split in routines, procedures or functions. This is the topic of the next chapter, which introduces also some advanced elements of Pascal.

Next Chapter: Procedures