A Guided Intro to the Free Pascal Language

This short guide is designed as an introduction to the Free Pascal programming language for anyone who either isn't familiar with writing computer software or perhaps is not acquainted with Free Pascal.

To accomplish this goal, the guide walks you through an example program written using the Lazarus IDE. The example program creates a visual window or "form" to both display and record SQL statements and related database activity. These SQL statements are dynamically generated by a variety of Entity Framework data providers and are normally hidden. In brief, this program shows you what's happening when certain information is requested on your computer.

The SQL Monitor example program

Source Code Files

Typically, Pascal source code is split into two or more files: a program source, and one or more unit sources. The program source contains a main statement block that executes when the program begins, which then hands off code execution to routines in other units used by the program. Unit files typically contain the main logic of your program and may contain visual resources such as custom designed forms and controls.

Program Source Code

Below is the program source code for the SQL monitoring example program. After the code listing is an explanation of the purpose of each line of Pascal code.
program sqlmon;

{$mode delphi}

uses
  Codebot.System,
  Codebot.Unique,
  Interfaces, Forms, Main;

{$r *.res}

begin
  SqlInstance := UniqueInstance(SqlPort + 1);
  if SqlInstance.Original then
  begin
    RequireDerivedFormResource := True;
    Application.Scaled := True;
    Application.Initialize;
    Application.CreateForm(TSqlForm, SqlForm);
    Application.Run;
  end
  else
    SqlInstance.SendMessage('wake up');
end.
All Pascal programs start with a program statement. The statement declares that the project should be built as a binary program of some arbitrary name.

Optionally, a mode directive can be used once in any source file to tell the compiler to make use of certain language semantics. In this case, we are using Delphi language semantics.

Next, we have the option to include a uses clause. This clause instructs the compiler which unit files to use during compilation and linking. These can be either unit source code files or precompiled units, and are similar to the "using" statements available in C#.

A resource file can be linked to your program. This file can contain your main icon, version information, and other resources. The asterisk wildcard tells the compiler to look for a resource file name matching the program name.

Every Pascal program is required to end with a main block that is surrounded by "begin" and "end". Note the period "." at the end in the last line.

In this program, the first statement of the main block determines if the program is already running an original instance. If it's running as the original instance, the application is initialized, scaled to the user's dpi, and the main form is created and run. Otherwise, the original program instance is sent a message to wake up, bringing it into the foreground

Unit Source Code

Below is a listing of the main unit source code for the example program. The main unit is paired with a visually designed custom form that owns a few associated controls and components. A special external resource file is bound to the unit storing information such as form layout, control properties, and mapping of events to their handling methods.

As the main unit source is a bit longer than the program source, for clarity I have broken down the unit source into several sections immediately followed by an explanation of that section. In reality, these sections come from one file.

Interface Section



Pascal units are divided into at least two sections: an interface section, and an implementation section. The interface section may contain a uses clause and the public declaration of variables, constants, types, and routines. The implementation that must follow can contain the same kinds of information, but it is private to the unit. Additionally, the actual implementation of routines cannot be placed in the interface section, rather it must be in the implementation section.

Here is an example interface section taken from the main unit of the SQL monitoring program.
unit Main;

{$mode delphi}

interface

uses
  Codebot.System,
  Codebot.Unique,
  Codebot.Networking,
  Forms, Controls, StdCtrls, ExtCtrls;

type
  TSqlForm = class(TForm)
    SqlMemo: TMemo;
    ClearButton: TButton;
    CloseTimer: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure CloseTimerTimer(Sender: TObject);
    procedure ClearButtonClick(Sender: TObject);
  private
    FSocket: TSocket;
    FMessage: string;
    procedure ThreadSocket(Thread: TSimpleThread);
    procedure ThreadSync;
    procedure WakeUp(const Message: string);
  end;

var
  SqlInstance: TUniqueInstance;
  SqlForm: TSqlForm;

const
  SqlPort = 6060;
All Pascal units start with a unit statement. The statement declares the unit with an arbitrary name. This name can then be used by other units or programs to refer to the public declarations within the unit.

Free Pascal optionally allows units to declare a mode directive to define language semantics for that file. Separate programs and units can have different semantics without penalty.

Again the interface section of a unit can have a uses clause. When a uses clause appears in an interface section that unit may then make use of the routines, types, variables, and constants defined in the interface sections of other units included in the uses clause.

Global types can be declared in the interface section of a unit, making them available to other program or unit files. In this main unit, a form class is defined with the help of a visual design editor. When interacting with a design editor, code will be automatically added and removed by the designer if relates to the visual classes within your unit. You can also bypass the designer and manually manage code in your visual classes.

Global variables and constants can be placed in the interface section of a unit, making them available to other program or unit files. Variables can be changed and the value might be unknown at compile time. Constants cannot change and must reference a known value before compilation.

Implementation Section



All Pascal units are required to have an implementation section. Everything within the section is automatically private to that unit. Below is the first part of the implementation section in the main unit of our example program.
implementation

{$r *.lfm}

procedure TSqlForm.FormCreate(Sender: TObject);
begin
  Caption := 'SQL Monitor on Port ' + IntToStr(SqlPort);
  ClientWidth := SqlMemo.Left * 2 + SqlMemo.Width;
  ClientHeight := ClearButton.Top + ClearButton.Height + SqlMemo.Left;
  SqlMemo.Anchors := [akLeft, akTop, akRight, akBottom];
  ClearButton.Anchors := [akRight, akBottom];
  TSimpleThread.Create(ThreadSocket);
  SqlInstance.OnMessage := WakeUp;
end;
The section starts with the implementation keyword and can be followed by an optional uses clause and more implementation declarations or code.

When designing code with visual classes, such as a form, a resource directive causes resources generated by the visual designer to compile and link to your program. The asterisk wildcard tells the compiler to look for a lfm resource file with a name matching that of the unit name.

Routine and method implementation code can only be placed inside the implementation section. In this case, the first method we've implemented is a form create notify event handler method. The sender argument tells us which form is being created and is wired up as an event handler to an instance of the TSqlForm class for us automatically using the resources from the visual designer.

The first line of code in our create event handler method sets the form caption to include the socket port we're using to communicate with Entity Framework providers. The next bits manually resizes our form to match its content.

We then create a secondary thread to accept and record messages received from Entity Framework providers.

The last statement in our form create event handler method manually assigns a message event handler method to our program. If our program is the original instance, we can use this handler to take action on messages sent to our program from other instances that the user attempted to run.

Secondary Thread



Pascal programs can have one or more threads running within them. Threads are essentially parallel units of code execution that can run at the same time. Each program is assigned one thread of execution when it starts, but more threads can be requested by your program. In our example, we're using a secondary thread to receive and record SQL information for diagnosis later.
procedure TSqlForm.ThreadSocket(Thread: TSimpleThread);
var
  Server, Client: TSocket;
  S: string;
begin
  Thread.FreeOnTerminate := True;
  Server := TSocket.Create;
  Client := TSocket.Create;
  FSocket := Server;
  try
    Server.Listen(SqlPort);
    while Server.State <> ssClosed do
    begin
      if not Server.Accept(Client) then
        Continue;
      while Client.Connected do
        if Client.Read(S) > 0 then
        begin
          FMessage := S;
          Thread.Synchronize(ThreadSync);
        end;
    end;
  finally
    FSocket := nil;
    Client.Free;
    Server.Free;
  end;
end;
The next method in our unit is responsible for running our secondary thread. It declares some local variables and begins execution by telling the thread to clean itself up automatically when it's finished.

Next communication sockets are created. In this example, the server socket instance is then stored for usage elsewhere.

The server socket is told to listen on a specific port. While the server remains in a listening state, it waits to accept client sockets that want to send us SQL activity messages.

While a client socket stays connected we read whatever it sends and record the message. We then synchronize our secondary thread to update the user interface with the newly received message.

We detect the request to terminate the secondary thread by stopping execution when our server socket is closed by the main thread. Before the thread exits we signal the main thread it is safe to close and clean up our local variables.

Synchronization Method



The thread synchronization method is used to access user interface elements by the secondary thread. Most native user interface toolkits are not thread safe and are meant to be used only by the main program thread. Synchronize methods help us to work around this restriction.
procedure TSqlForm.ThreadSync;
const
  Max = High(Integer) div 4;
begin
  SqlMemo.ScrollBy(0, Max);
  SqlMemo.SelStart := Max;
  SqlMemo.SelLength := 0;
  SqlMemo.SelText := FMessage;
end;
The method begins by declaring a constant for use with scrolling our memo control. We then scroll the memo to the bottom and reset the selection before adding our new message. Usually, synchronization methods are this short.

Safely Closing



When the user attempts to close the program we need to consider how to safely request and wait for our secondary thread to terminate. We can tackle that problem using the two methods below.
procedure TSqlForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose := FSocket = nil;
  if CanClose then Exit;
  FSocket.Close;
  CloseTimer.Enabled := True;
end;

procedure TSqlForm.CloseTimerTimer(Sender: TObject);
begin
  CloseTimer.Enabled := False;
  Close;
end;
First we use a close query event handler method to detect if the form is allowed to close. The form can close only when the server socket is set to nothing. Otherwise the secondary thread is still busy and we ask it stop by closing the server socket and enabling a brief delay.

In the brief delay method we disable further delay notifications and request the form to try to close again. If the thread is not done yet this sequence will repeat itself.

Other Methods



At the end of our main unit we have a few extra methods.
procedure TSqlForm.ClearButtonClick(Sender: TObject);
begin
  SqlMemo.Lines.Clear;
end;

procedure TSqlForm.WakeUp(const Message: string);
begin
  Application.BringToFront;
  Application.MainForm.Show;
end;

end.
The clear button event handler method is fired when the user clicks the clear button. It simply clears the memo of any activity we've recorded thus far.

The wake up event handler method is executed in the main thread whenever another program instance was launched. Instead of launching a second instance we activate and attempt to bring our program to the foreground. Some platform window managers won't allow this, but the user might receive a flashing icon over our program in their taskbar instead.

Finally, our main unit is terminated with a single "end." statement. Again, note the "." as the final character.

Closing Summary

Hopefully, after having read through this article you're now better able to understand how the Free Pascal language is structured and some of its features. In the opinion of the author, when paired with Lazarus the Free Pascal environment is quite suitable for rapidly creating desktop programs. The way it enforces certain aspects of code organization helps guide programmers into writing understandable and maintainable code.

If you would like to try Free Pascal and the Lazarus IDE, you can visit the download page where I maintain bundled packages for Windows, Mac, Linux, and Raspberry Pi.