Lecture 2

To review the material from this lecture, read the following sections of our Pascal Made Simple textbook:

Here are a few more notes on various topics.

program

The program element at the top of a Pascal program is entirely optional in Free Pascal. I think that a comment describing what the program does is more useful than a program header in any case.

case insensitivity

Pascal is completely case-insensitive. You can write

var
  j := 4;
begin
  writeln(j + 1);

or

VAR
  J := 4;
BEGIN
  WRITELN(J + 1);

or mix both styles within the same program.

I like writing keywords in lowercase and using function names that begin with a lowercase letter, so that's the style used in all examples in this course.

calling library functions

The Pascal Run-Time Library contains thousands of built-in functions that you can call. I've chosen several dozen of the most useful functions and listed them on a page called Run-Time Library Quick Reference. You will want to refer to this often when writing Pascal code for this class.

In Pascal, a function takes one or more arguments and returns a value. A procedure is like a function, but returns no value.

In the library quick reference, a function signature (i.e. the line of text indicating the function's name, parameter types and return type) looks like this:

function stringOfChar(c: char; n: integer) : string

This means that the function stringOfChar takes two parameters, a char and an integer. It returns a string. The names “c” and “n” appear in the function documentation here, but you don't type them when calling the function. You can call this function like this:

stringOfChar(4, 'm');           // returns 'mmmm'

Similarly, a procedure's signature looks like this:

procedure gotoXY(x: integer; y: integer)

Soon, we will learn to write our own functions and procedures in this course. When we do so, we will use the same syntax described here.

break and continue

Free Pascal includes two statements break and continue that can terminate the current iteration of a loop. They were not in classic Pascal and are not covered in Pascal Made Simple.

break

The break statement breaks out of the nearest enclosing for, while, or repeat loop.

Here is a program that looks for the letter 'x' in a string, and terminates the search as soon as an 'x' is seen. It illustrates two ways to accomplish this: one using break and one without.

// Search for the letter 'x' in a string.

{$mode delphi}

var
  s: string;
  i: integer;
  found: boolean;
  
begin
  write('text: ');
  readln(s);
  
  // early exit without break
  i := 1;
  while (i <= length(s)) and (s[i] <> 'x') do
    i := i + 1;
  if i <= length(s) then
    found := true
  else
    found := false;

  // early exit with break
  found := false;
  for i := 1 to length(s) do
    if s[i] = 'x' then
      begin
        found := true;
        break;
      end;
      
  writeln(found);
end.

continue

The continue statement continues with the next iteration of the nearest enclosing for, while, or repeat loop.

If continue is executed during the last iteration of a for loop, the loop exits. When continue is executed in a while or repeat loop, the loop condition is tested before beginning a new iteration; if it is false (for while) or true (for repeat) then the loop exits.

dynamic arrays

The Pascal Made Simple book only discusses static arrays, which have a fixed size: they cannot grow or shrink as a program runs.

In this course we will also be using dynamic arrays. A dynamic array holds a variable number of elements and can grow or shrink as the program runs. You can declare a dynamic array like this:

var
  a: array of integer;

Before you can use a dynamic array, you must set its length by calling setLength:

setLength(a, 100);

Dynamic arrays are always indexed from 0, so after the call above the array will hold elements with indices from 0 to 99. When growing a dynamic array, setLength sets any newly allocated elements to zero.

Like static arrays, you can use the syntax a[i] to read from or write to a dynamic array:

a[44] := 33;

a[44] := a[44] + 1;

Like static arrays, dynamic arrays can be multidimensional. Here's how to declare a multidimensional dynamic array:

var
  d: array of array of integer;

To set the dimensions of such an array, call setLength and pass each dimension as a separate parameter:

setLength(d, 100, 20);

Like static arrays, you can access elements of a multidimensional dynamic array using either of two syntaxes: a[i][j] or a[i, j].

execution speed

Computers are incredibly fast. Below is a program that performs a billion integer additions and reports the time to perform one addition on average. By making small changes to this program, you can measure how long other operations take as well.

Recall that

On my laptop, operations in Pascal take approximately this long in nanoseconds:

integer add

0.3

integer multiply

0.9

integer div

11.5

integer mod

11.3

floating-point add

2.0

floating-point multiply

2.0

floating-point division (/)

3.5



{$mode delphi}

uses dateutils, sysutils;

const
  Iterations = 1000 * 1000 * 1000;

var
  start, stop: TDateTime;
  
  x: integer;
  sum: integer;
  perIter: real;

begin
  start := now();
  
  sum := 0;
  for x := 1 to iterations do
    sum := sum + x;
  
  stop := now();
  
  perIter := millisecondsBetween(start, stop) * 1000 * 1000 / Iterations;
  writeln(perIter:0:2, ' ns per iteration');
end.

goto

Generally we don't have much use for goto, but it's interesting to write a loop using it instead of for or while. The Pascal compiler translates for or while loops into machine code that looks a lot like this.

label
  loop;
  
var
  i: integer;
  
begin
  i := 1;
  
 loop:
  writeln(i);
  i := i + 1;
  if i <= 10 then
    goto loop;
end.

dice

Here's a program that simulates throwing 2 6-sided dice a given number of times. It uses an array to keep track of the number of times that each outcome has been seen, and prints a histogram at the end.

var
  n: integer;
  roll, i: integer;
  
  count: array[2..12] of integer;
  
begin
  randomize;
  
  write('how many throws? ');
  readln(n);
  
  for i := 2 to 12 do
    count[i] := 0;
    
  for i := 1 to n do
    begin
      roll := (random(6) + 1) + (random(6) + 1);
      count[roll] := count[roll] + 1;
    end;
    
  for i := 2 to 12 do
    writeln(i:2, ': ', stringOfChar('*', count[i]));
end.

memory allocator

Here's a program that tries to determine how much memory we can allocate using setLength.

{$mode delphi}

var
  a: array of integer;
  size: int64 = 1;
  
begin
  while true do
    begin
      setLength(a, size);
      writeln('allocated ', size, ' elements');
      size := size * 2;
    end;
end.