DevTools

Cheatsheet Pascal

Linguagem estruturada clássica para ensino e desenvolvimento (Free Pascal/Delphi)

Back to languages
Pascal
105 cards found
Categories:
Versions:

Basic and Structure


14 cards
Program Structure
program MyProgram;

uses SysUtils;

var
  name: string;

begin
  WriteLn('Hello World!');
  Write('Name: ');
  ReadLn(name);
  WriteLn('Hello, ', name);
end.

A Pascal program starts with program, followed by uses (libraries), var (variables) and the begin...end. block (with a final period).

Arithmetic Operators
var
  a, b: integer;
  r: real;

begin
  a := 10; b := 3;
  WriteLn(a + b);   // 13 addition
  WriteLn(a - b);   // 7  subtraction
  WriteLn(a * b);   // 30 multiplication
  WriteLn(a div b); // 3  integer division
  WriteLn(a mod b); // 1  remainder
  r := a / b;       // 3.33 real division
end.

div is integer division and mod the remainder. The / operator always returns real, even with integer operands.

The in Operator (Set)
var
  x: integer;
  c: char;

begin
  x := 5;
  if x in [1..10] then
    WriteLn('between 1 and 10');

  c := 'a';
  if c in ['a', 'e', 'i', 'o', 'u'] then
    WriteLn('vowel');
end.

The in operator checks membership in a set. [1..10] is a range and [...] a list of values. Widely used in validations.

Simple Enumerated Type
type
  TDay = (Mon, Tue, Wed, Thu, Fri, Sat, Sun);

var
  d: TDay;

begin
  d := Mon;
  if d = Mon then
    WriteLn('Start of the week');
end.

An enumerated type lists fixed values between parentheses. It makes the code more readable and safer than using loose integers.

Data Types
var
  i: integer;    // integer (32-bit)
  b: byte;       // 0..255
  r: real;       // real number
  c: char;       // 1 character
  s: string;     // dynamic string
  ok: boolean;   // true/false
  d: double;     // double precision
  n: int64;      // 64-bit integer

Pascal is strongly typed: each variable has a fixed type. integer and int64 for integers, real/double for decimals, boolean for logic values.

Comparison Operators
var
  x: integer;

begin
  x := 5;
  WriteLn(x = 5);   // true  equal
  WriteLn(x <> 3);  // true  not equal
  WriteLn(x > 3);   // true  greater
  WriteLn(x <= 5);  // true  less or equal
end.

Equality is = (a single equals sign) and inequality is <>. The operators >, <, >= and <= compare order.

Comments
// single-line comment

{ comment between
  braces }

(* comment between
   parenthesis-asterisk *)

begin
  WriteLn('Hello'); // inline
end.

Pascal accepts three comment styles: // (line), { } and (* *) (block). Block comments can span multiple lines.

Subranges
type
  TGrade = 0..20;
  TVowels = 'a'..'z';

var
  grade: TGrade;

begin
  grade := 15;
  // grade := 25;  // ERROR: out of range
end.

A subrange restricts a variable to a range of values (e.g. 0..20). The compiler can validate the assigned limits.

Variables and Assignment
var
  x, y, z: integer;
  name: string;

begin
  x := 10;       // assignment with :=
  y := x * 2;    // 20
  name := 'Anna';
  z := x + y;
end.

Assignment uses := (colon and equals), unlike = which is comparison. Several variables of the same type are declared on the same line.

Logical Operators
var
  a, b: boolean;

begin
  a := true; b := false;
  WriteLn(a and b);  // false (AND)
  WriteLn(a or b);   // true  (OR)
  WriteLn(not a);    // false (negation)
  WriteLn(a xor b);  // true  (exclusive OR)
end.

The logical operators are spelled out: and, or, not (negation) and xor (exclusive OR). They operate on boolean.

Formatted Output
var
  n: integer;
  r: real;

begin
  n := 42;
  r := 3.14159;
  WriteLn(n:5);     // "   42" (width 5)
  WriteLn(r:8:2);   // "    3.14" (2 decimals)
  Write('no ');
  WriteLn('break'); // same line
end.

WriteLn writes with a line break and Write without one. The syntax value:width:decimals formats the output aligned.

Constants
const
  PI = 3.14159;
  MAX = 100;
  NAME = 'Pascal';
  ACTIVE = true;

begin
  WriteLn(PI * 2);
  // PI := 3;  // ERROR: constant
end.

Constants are declared with const and cannot be changed. The type is inferred from the value. Useful for fixed values like PI or limits.

String Concatenation
var
  name, greeting: string;

begin
  name := 'Anna';
  greeting := 'Hello, ' + name + '!';
  WriteLn(greeting);  // Hello, Anna!
end.

The + operator concatenates strings. To join text with numbers, convert first with IntToStr() or use WriteLn with commas.

Reading Input
var
  name: string;
  age: integer;

begin
  Write('Name: ');
  ReadLn(name);

  Write('Age: ');
  ReadLn(age);

  WriteLn('Hello ', name, ', ', age);
end.

ReadLn reads a line from the keyboard into the variable. Write shows the prompt without a line break before the read.

Flow Control


12 cards
If / Else
if age >= 18 then
  WriteLn('Adult')
else if age >= 12 then
  WriteLn('Teenager')
else
  WriteLn('Child');

The if/else evaluates conditions in order. Parentheses are not required and no semicolon is used before the else.

For (Ascending)
var
  i: integer;

begin
  for i := 1 to 10 do
    WriteLn(i);
end.

The for with to counts upward. The control variable must be an ordinal type (integer, char, enum). Do not modify it inside the loop.

Break
var
  i: integer;

begin
  for i := 1 to 100 do
  begin
    if i = 50 then
      Break;  // exits the loop
    WriteLn(i);
  end;
end.

Break immediately ends the loop (for, while or repeat) and continues after it. Useful to exit when a result is found.

If with begin/end Block
if x > 0 then
begin
  y := x * 2;
  WriteLn('positive: ', y);
end
else
begin
  y := 0;
  WriteLn('not positive');
end;

To run several statements in a branch, group them with begin...end. Without the block, only the first statement belongs to the if.

For (Descending)
var
  i: integer;

begin
  for i := 10 downto 1 do
    WriteLn(i);
  // 10, 9, 8, ... 1
end.

The for with downto counts downward. Useful for countdowns or traversing arrays from the end to the start.

Continue
var
  i: integer;

begin
  for i := 1 to 10 do
  begin
    if i mod 2 = 0 then
      Continue;  // skips even numbers
    WriteLn(i);  // odd numbers only
  end;
end.

Continue jumps to the next iteration of the loop, skipping the rest of the current block. Here it prints only the odd numbers.

Case
case day of
  1: WriteLn('Monday');
  2: WriteLn('Tuesday');
  3..5: WriteLn('Midweek');
  6, 7: WriteLn('Weekend');
else
  WriteLn('Invalid');
end;

The case selects by value. It accepts single values, ranges (3..5) and lists (6, 7). The else handles the remaining cases.

While
var
  x: integer;

begin
  x := 5;
  while x > 0 do
  begin
    WriteLn(x);
    x := x - 1;
  end;
end.

The while repeats while the condition is true. It checks the condition before each iteration, so the block may never run.

Exit
function Divide(a, b: integer): integer;
begin
  if b = 0 then
  begin
    WriteLn('Division by zero');
    Exit;  // exits the function
  end;
  Result := a div b;
end;

Exit immediately ends the current function or procedure. In functions, it can return a value with Exit(value) (modern Delphi/FPC).

Case with Strings
case command of
  'quit': Close;
  'help': ShowHelp;
  'save': Save;
else
  WriteLn('Unknown command');
end;

In Free Pascal and Delphi the case also accepts strings. Each branch compares against a string constant. Cleaner than several if statements.

Repeat / Until
var
  x: integer;

begin
  x := 0;
  repeat
    x := x + 1;
    WriteLn(x);
  until x >= 5;
end.

The repeat/until runs the block before checking the condition, guaranteeing at least one execution. It repeats until the condition becomes true.

Nested Loops
var
  i, j: integer;

begin
  for i := 1 to 3 do
    for j := 1 to 3 do
      WriteLn('i=', i, ' j=', j);
end.

You can nest loops to traverse matrices or generate combinations. Each level uses its own control variable (i, j).

Functions and Procedures


13 cards
Simple Procedure
procedure Greet(name: string);
begin
  WriteLn('Hello, ', name, '!');
end;

begin
  Greet('Anna');
  Greet('Ray');
end.

A procedure is a subprogram that performs actions without returning a value. It is declared before the main begin and called by name.

const Parameter
procedure Print(const s: string);
begin
  WriteLn(s);
  // s := 'x';  // ERROR: cannot modify
end;

The const passes by reference but prevents modification. It avoids copying large types (strings, records) while keeping read-only safety.

Default Parameters
procedure Log(msg: string; level: integer = 1);
begin
  WriteLn('[', level, '] ', msg);
end;

begin
  Log('error', 3);  // [3] error
  Log('info');      // [1] info
end.

Parameters with a default value (e.g. level: integer = 1) can be omitted in the call. They must come at the end of the parameter list.

Variable Scope
var
  globalVar: integer;  // visible in the whole program

procedure Test;
var
  localVar: integer;  // only visible here
begin
  localVar := 5;
  globalVar := localVar;
end;

Variables declared at the top are global; inside a routine they are local. Local variables cease to exist when the routine ends.

Function with Return Value
function Add(a, b: integer): integer;
begin
  Add := a + b;  // return via the name
end;

begin
  WriteLn(Add(2, 3));  // 5
end.

A function returns a value, assigned to the function name itself (here Add := ...). The return type comes after :.

Open Array
function Sum(const nums: array of integer): integer;
var
  i: integer;
begin
  Result := 0;
  for i := Low(nums) to High(nums) do
    Result := Result + nums[i];
end;

begin
  WriteLn(Sum([1, 2, 3, 4]));  // 10
end.

An array of the a parameter accepts arrays of any size. Low() and High() give the bounds and you can pass [...] literals.

Forward Declaration
procedure B; forward;

procedure A;
begin
  B;  // calls B declared ahead
end;

procedure B;
begin
  WriteLn('B');
end;

The forward directive declares a routine before its implementation, allowing mutual references between procedures (e.g. A calls B and B calls A).

Result (Modern Form)
function Square(x: integer): integer;
begin
  Result := x * x;
end;

function IsEven(n: integer): boolean;
begin
  Result := (n mod 2 = 0);
end;

The special variable Result holds the return value in a more readable way. It is the preferred form in modern Delphi and Free Pascal.

Recursion
function Factorial(n: integer): int64;
begin
  if n <= 1 then
    Result := 1
  else
    Result := n * Factorial(n - 1);
end;

begin
  WriteLn(Factorial(5));  // 120
end.

A recursive function calls itself. It needs a base case (n <= 1) to terminate. Here it computes the factorial of n.

Anonymous Functions (Delphi/FPC)
type
  TIntFunc = reference to function(x: integer): integer;

var
  double: TIntFunc;

begin
  double := function(x: integer): integer
  begin
    Result := x * 2;
  end;

  WriteLn(double(5));  // 10
end.

Anonymous functions (lambdas) use reference to function. They can be assigned to variables and passed the arguments, like in other modern languages.

Parameter by Reference (var)
procedure Increment(var x: integer);
begin
  x := x + 1;  // changes the original variable
end;

var
  n: integer;
begin
  n := 10;
  Increment(n);
  WriteLn(n);  // 11
end.

The var passes the parameter by reference: the function changes the original variable. Without var, it receives only a copy (by value).

Function Overloading
function Max(a, b: integer): integer; overload;
begin
  if a > b then Result := a else Result := b;
end;

function Max(a, b: real): real; overload;
begin
  if a > b then Result := a else Result := b;
end;

The overload allows several functions with the same name but different parameters. The compiler picks the right version based on the argument types.

Higher-Order Functions
type
  TOperation = function(a, b: integer): integer;

function Apply(x, y: integer; op: TOperation): integer;
begin
  Result := op(x, y);
end;

function Add(a, b: integer): integer;
begin
  Result := a + b;
end;

You can pass functions the parameters using a function type (function(a,b): integer). This allows reusable higher-order functions.

Data Structures


14 cards
Static Array
var
  arr: array[1..5] of integer;
  i: integer;

begin
  for i := 1 to 5 do
    arr[i] := i * 10;

  WriteLn(arr[1]);  // 10
  WriteLn(arr[5]);  // 50
end.

A static array has a fixed size defined at compile time (array[1..5]). The starting index can be any ordinal value, here it starts at 1.

Record with Methods
type
  TPoint = record
    x, y: integer;
    procedure Move(dx, dy: integer);
  end;

procedure TPoint.Move(dx, dy: integer);
begin
  x := x + dx;
  y := y + dy;
end;

Modern records (Delphi/FPC) can have methods and properties. The syntax TPoint.Move implements the method declared in the record.

Sets
type
  TVowels = set of char;

var
  v: TVowels;

begin
  v := ['a', 'e', 'i', 'o', 'u'];
  if 'a' in v then
    WriteLn('is a vowel');
end.

A set stores unique values of an ordinal type. The in operator checks membership. Useful for flags and small collections.

TDictionary
uses Generics.Collections;

var
  dict: TDictionary<string, integer>;
begin
  dict := TDictionary<string, integer>.Create;
  try
    dict.Add('Anna', 30);
    dict.Add('Ray', 25);
    WriteLn(dict['Anna']);  // 30
  finally
    dict.Free;
  end;
end.

TDictionary<K,V> stores key-value pairs. Access the value through the key (e.g. dict["Anna"]). Equivalent to a map/hashtable.

Dynamic Array
var
  dyn: array of integer;

begin
  SetLength(dyn, 5);  // allocates 5 elements
  dyn[0] := 10;       // starts at 0
  dyn[4] := 50;

  WriteLn(Length(dyn));  // 5
  WriteLn(Low(dyn));     // 0
  WriteLn(High(dyn));    // 4
end.

A dynamic array (array of) is resizable with SetLength. It always starts at index 0. Length, Low and High give the bounds.

Variant Record
type
  TShape = record
    case kind: char of
      'c': (radius: real);
      'r': (width, height: real);
  end;

var
  f: TShape;
begin
  f.kind := 'c';
  f.radius := 5.0;
end.

A variant record has fields that share memory according to a discriminant field (case). Similar to a union in C.

Set Operations
var
  A, B, C: set of integer;

begin
  A := [1, 2, 3];
  B := [2, 3, 4];
  C := A + B;  // union [1,2,3,4]
  C := A - B;  // difference [1]
  C := A * B;  // intersection [2,3]
end.

Sets support mathematical operations: + (union), - (difference) and * (intersection). Ideal for set logic.

Array and Record Constants
const
  Days: array[1..7] of string =
    ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun');

  Origin: TPoint = (x: 0; y: 0);

begin
  WriteLn(Days[1]);  // Mon
end.

You can create constant arrays and records with fixed initial values. Arrays use (...) and records use (field: value; ...).

Multidimensional Array
var
  matrix: array[1..3, 1..3] of integer;
  i, j: integer;

begin
  for i := 1 to 3 do
    for j := 1 to 3 do
      matrix[i, j] := i * j;

  WriteLn(matrix[2, 3]);  // 6
end.

A multidimensional array uses several indexes separated by commas (array[1..3, 1..3]). Ideal for matrices and two-dimensional grids.

With (Record Shortcut)
var
  p: TPerson;

begin
  with p do
  begin
    name := 'Anna';
    age := 30;
    active := true;
  end;
end.

The with avoids repeating the record name when accessing several fields. Inside the block, name refers to p.name. Use with moderation.

TStringList
uses Classes;

var
  list: TStringList;
begin
  list := TStringList.Create;
  try
    list.Add('item1');
    list.Add('item2');
    WriteLn(list.Count);        // 2
    WriteLn(list.IndexOf('item1')); // 0
  finally
    list.Free;
  end;
end.

TStringList is a dynamic string list from the RTL. It offers Add, IndexOf, Sort and Count. Create with Create and release with Free.

Simple Record
type
  TPerson = record
    name: string;
    age: integer;
    active: boolean;
  end;

var
  p: TPerson;
begin
  p.name := 'Anna';
  p.age := 30;
  p.active := true;
end.

A record groups fields of different types in one structure. Fields are accessed with a dot (p.name). It is the equivalent of a struct.

Enumerations (enum)
type
  TColor = (Red, Green, Blue);

var
  c: TColor;

begin
  c := Green;
  if c = Green then
    WriteLn('Green');
  WriteLn(Ord(c));  // 1 (position)
end.

An enumeration defines an ordered set of named values. Ord() returns the position (starting at 0). More readable than integers.

Generics (TList)
uses Generics.Collections;

var
  nums: TList<integer>;
begin
  nums := TList<integer>.Create;
  try
    nums.Add(10);
    nums.Add(20);
    nums.Sort;
    WriteLn(nums[0]);  // 10
  finally
    nums.Free;
  end;
end.

Generics (TList<integer>) create safe typed collections. Generics.Collections brings TList, TDictionary and other dynamic lists.

Strings and Conversions


12 cards
Length and Copy
var
  s: string;

begin
  s := 'Hello World';
  WriteLn(Length(s));      // 11
  WriteLn(Copy(s, 1, 5));  // 'Hello'
  WriteLn(Copy(s, 7, 5));  // 'World'
end.

Length() returns the number of characters. Copy(s, start, n) extracts a substring starting at start with n characters.

StringReplace
uses SysUtils;

var
  s: string;
begin
  s := 'hi world hi';
  s := StringReplace(s, 'hi', 'hello',
       [rfReplaceAll, rfIgnoreCase]);
  WriteLn(s);  // 'hello world hello'
end.

StringReplace() replaces text. rfReplaceAll swaps every occurrence and rfIgnoreCase ignores case.

Format
uses SysUtils;

begin
  WriteLn(Format('%d years', [30]));
  WriteLn(Format('%.2f', [3.14159]));  // 3.14
  WriteLn(Format('%s is %d', ['Anna', 30]));
  WriteLn(Format('%8d', [42]));  // aligned
end.

Format() builds strings with placeholders: %d (integer), %f (real), %s (string). The .2 sets the decimal places.

Uppercase and Lowercase
uses SysUtils;

var
  s: string;
begin
  s := 'Hello World';
  WriteLn(UpperCase(s));  // 'HELLO WORLD'
  WriteLn(LowerCase(s));  // 'hello world'
end.

UpperCase() converts to uppercase and LowerCase() to lowercase. They live in the SysUtils unit.

Trim
uses SysUtils;

var
  s: string;
begin
  s := '  text  ';
  WriteLn(Trim(s));       // 'text'
  WriteLn(TrimLeft(s));   // 'text  '
  WriteLn(TrimRight(s));  // '  text'
end.

Trim() removes spaces at the start and end. TrimLeft() only on the left and TrimRight() only on the right. Essential to clean input.

Char: Ord and Chr
var
  c: char;
  n: integer;

begin
  n := Ord('A');   // 65 (ASCII code)
  c := Chr(65);    // 'A'
  c := Chr(Ord('a') - 32);  // 'A'
  WriteLn(Succ('A'));  // 'B'
  WriteLn(Pred('B'));  // 'A'
end.

Ord() returns the numeric code of the character and Chr() does the inverse. Succ() and Pred() give the next/previous.

Pos (Search)
var
  s: string;
  p: integer;

begin
  s := 'Hello World';
  p := Pos('World', s);
  WriteLn(p);  // 7 (position)

  if Pos('xyz', s) = 0 then
    WriteLn('not found');
end.

Pos(sub, s) returns the position of the first occurrence (starting at 1) or 0 if not found. Useful to check presence.

String to Number
uses SysUtils;

var
  n: integer;
  r: real;
begin
  n := StrToInt('42');        // 42
  r := StrToFloat('3.14');    // 3.14
  n := StrToIntDef('abc', 0); // 0 (safe)
end.

StrToInt() and StrToFloat() convert strings into numbers and raise an exception if invalid. StrToIntDef() returns a default value instead of failing.

Concat and Length
var
  a, b, c: string;

begin
  a := 'Hello';
  b := 'World';
  c := Concat(a, ' ', b);
  WriteLn(c);          // 'Hello World'
  WriteLn(Length(c));  // 11
end.

Concat() joins several strings into one (an alternative to +). Length() returns the length. Strings in Pascal are dynamic.

Delete and Insert
var
  s: string;

begin
  s := 'Hello World';
  Delete(s, 1, 6);   // removes 6 chars
  WriteLn(s);        // 'World'

  Insert('!', s, 6);
  WriteLn(s);        // 'World!'
end.

Delete(s, start, n) removes n characters (modifies the string). Insert(txt, s, pos) inserts text at the given position.

Number to String
uses SysUtils;

var
  s: string;
begin
  s := IntToStr(42);        // '42'
  s := FloatToStr(3.14);    // '3.14'
  s := FloatToStrF(3.14159,
       ffFixed, 8, 2);      // '3.14'
end.

IntToStr() and FloatToStr() convert numbers into strings. FloatToStrF() lets you control the format and decimal places.

String with Quotes (escape)
var
  s: string;

begin
  s := 'He said ''hello''';
  WriteLn(s);  // He said 'hello'

  s := 'Line1' + #13#10 + 'Line2';
  WriteLn(s);  // two lines
end.

To include a single quote inside a string, double it (''). #13#10 inserts a line break (CR+LF) using character codes.

Pointers, Units and Exceptions


14 cards
Basic Pointers
var
  p: ^integer;
  x: integer;
begin
  x := 42;
  p := @x;       // address of x
  WriteLn(p^);   // 42 (dereference)
  p^ := 100;     // changes x
  WriteLn(x);    // 100
end.

A pointer (^integer) stores an address. @x gets the address and p^ accesses the pointed value (dereference).

Using a Unit
program Main;

uses MyUnit, SysUtils;

begin
  WriteLn(Add(2, 3));  // from MyUnit
end.

The uses clause imports units to access their functions and types. It can appear in the program or in another unit (interface or implementation).

Custom Exception
type
  EInsufficientBalance = class(Exception)
    constructor Create(value: real);
  end;

constructor EInsufficientBalance.Create(value: real);
begin
  inherited CreateFmt('Insufficient balance: %.2f',
    [value]);
end;

Create classes that inherit from Exception for specific errors. CreateFmt formats the message with parameters, like Format.

Bitwise Operations
var
  a, b: integer;
begin
  a := 12;  // 1100
  b := 10;  // 1010
  WriteLn(a and b);  // 8  (1000)
  WriteLn(a or b);   // 14 (1110)
  WriteLn(a xor b);  // 6  (0110)
  WriteLn(a shl 1);  // 24 (shift)
end.

The bitwise operators and, or, xor, shl and shr operate on the bits of the integer. Useful for flags and masks.

Dynamic Memory
var
  p: ^integer;
begin
  New(p);      // allocate memory
  p^ := 100;
  WriteLn(p^);
  Dispose(p);  // release memory
  p := nil;
end.

New() allocates memory for the pointed type and Dispose() releases it. Set the pointer to nil afterwards to avoid invalid accesses.

Try / Except
var
  x: integer;
begin
  try
    x := StrToInt('abc');
  except
    on E: EConvertError do
      WriteLn('Invalid number');
    on E: Exception do
      WriteLn('Error: ', E.Message);
  end;
end.

try..except catches exceptions. The on E: Type handles each exception type. E.Message gives the error description.

Typed Constants
const
  Threshold: integer = 100;  // mutable (FPC)

begin
  Threshold := 200;  // allowed
  WriteLn(Threshold);
end.

Typed constants (name: type = value) are actually initialized static variables: they keep the value between calls and can be changed.

Complete Program (example)
program Average;

uses SysUtils;

var
  grades: array of integer;
  i, sum: integer;

begin
  SetLength(grades, 3);
  sum := 0;
  for i := 0 to High(grades) do
  begin
    grades[i] := Random(20) + 1;
    sum := sum + grades[i];
  end;
  WriteLn('Average: ', sum / Length(grades):0:1);
end.

Complete example: allocates a dynamic array, fills it with Random, sums and computes the average. It shows the typical structure of a Pascal program.

GetMem and FreeMem
var
  ptr: Pointer;
begin
  GetMem(ptr, 1024);  // 1024 bytes
  // use ptr...
  FreeMem(ptr);       // release
  ptr := nil;
end.

GetMem() allocates a raw block of bytes and FreeMem() releases it. More flexible than New for variable-size buffers.

Try / Finally
var
  list: TStringList;
begin
  list := TStringList.Create;
  try
    list.Add('item');
    WriteLn(list.Count);
  finally
    list.Free;  // always runs
  end;
end.

try..finally guarantees the execution of the finally block even on error. It is the pattern for releasing resources (memory, files, objects).

Compiler Directives
{$IFDEF DEBUG}
  WriteLn('Debug mode active');
{$ENDIF}

{$MODE DELPHI}   // Delphi mode (FPC)
{$RANGECHECKS ON} // checks indexes

begin
  WriteLn('Hello');
end.

{$...} directives control compilation. {$IFDEF} compiles conditionally, {$MODE} sets compatibility and {$RANGECHECKS} validates indexes.

Structure of a Unit
unit MyUnit;

interface

uses SysUtils;

function Add(a, b: integer): integer;

implementation

function Add(a, b: integer): integer;
begin
  Result := a + b;
end;

end.

A unit is a reusable module. The interface section declares what is public and implementation holds the code. It is used with uses.

Raise (throw an exception)
procedure Validate(age: integer);
begin
  if age < 0 then
    raise Exception.Create('Invalid age');
end;

raise throws an exception manually. Exception.Create(msg) creates the exception with a message. It interrupts the flow up to the nearest except.

Type Aliases
type
  TName = string;
  TAge = integer;
  TMatrix = array of array of real;

var
  name: TName;
  m: TMatrix;
begin
  name := 'Anna';
end.

The type creates alternative names for existing types, improving readability. TName is just an alias for string.

Input/Output and Files


12 cards
Write and WriteLn
begin
  Write('No break ');
  WriteLn('with break');
  WriteLn('A', 'B', 'C');   // ABC
  WriteLn(10, ' ', 20);     // 10 20
  WriteLn(3.14:6:2);        //   3.14
end.

Write prints without moving to a new line and WriteLn does. They accept several comma-separated arguments and :width:decimals formatting.

Append
var
  f: TextFile;

begin
  AssignFile(f, 'log.txt');
  Append(f);             // append at the end
  WriteLn(f, 'New entry');
  CloseFile(f);
end.

Append opens an existing file to append at the end, without erasing the previous content. Ideal for log files.

Check Existence
uses SysUtils;

begin
  if FileExists('data.txt') then
    WriteLn('exists')
  else
    WriteLn('does not exist');

  if DirectoryExists('C:\temp') then
    WriteLn('folder exists');
end.

FileExists() checks whether a file exists and DirectoryExists() whether a folder exists. They live in the SysUtils unit.

Read and ReadLn
var
  name: string;
  age: integer;

begin
  ReadLn(name);       // reads a line
  ReadLn(age);        // reads an integer
  WriteLn(name, ' ', age);
end.

ReadLn reads a full line from the keyboard and converts it to the variable type. Read reads without consuming the line break.

Binary File (typed)
type
  TRecord = record
    id: integer;
    name: string[50];
  end;

var
  f: file of TRecord;
  reg: TRecord;
begin
  AssignFile(f, 'data.dat');
  Rewrite(f);
  reg.id := 1;
  reg.name := 'Anna';
  Write(f, reg);
  CloseFile(f);
end.

A file of TRecord stores fixed-size records in binary. Write(f, reg) and Read(f, reg) read/write complete records.

Delete and Rename
var
  f: TextFile;

begin
  AssignFile(f, 'old.txt');
  Erase(f);          // deletes the file

  AssignFile(f, 'new.txt');
  Rename(f, 'new2.txt');  // renames
end.

Erase() deletes the associated file and Rename() changes the name. The variable must be linked with AssignFile but not open.

Write a Text File
var
  f: TextFile;

begin
  AssignFile(f, 'data.txt');
  Rewrite(f);            // create/write
  WriteLn(f, 'Line 1');
  WriteLn(f, 'Line 2');
  CloseFile(f);
end.

AssignFile links the variable to the file, Rewrite opens it for writing (creates a new one), you write with WriteLn(f, ...) and close with CloseFile.

Read a Binary File
var
  f: file of TRecord;
  reg: TRecord;

begin
  AssignFile(f, 'data.dat');
  Reset(f);
  while not EOF(f) do
  begin
    Read(f, reg);
    WriteLn(reg.id, ' ', reg.name);
  end;
  CloseFile(f);
end.

Binary reading uses Read(f, reg) inside while not EOF(f). Each iteration loads a complete record of the structure.

TFileStream
uses Classes, SysUtils;

var
  fs: TFileStream;
  s: string;
begin
  fs := TFileStream.Create('data.bin',
        fmCreate);
  try
    s := 'Hello';
    fs.WriteBuffer(s[1], Length(s));
  finally
    fs.Free;
  end;
end.

TFileStream gives full control over binary reading/writing. fmCreate creates the file and WriteBuffer writes raw bytes.

Read a Text File
var
  f: TextFile;
  line: string;

begin
  AssignFile(f, 'data.txt');
  Reset(f);              // open for reading
  while not EOF(f) do
  begin
    ReadLn(f, line);
    WriteLn(line);
  end;
  CloseFile(f);
end.

Reset opens the file for reading. The while not EOF(f) loop goes through to the end, reading each line with ReadLn(f, line).

Size and Position (binary)
var
  f: file of TRecord;

begin
  AssignFile(f, 'data.dat');
  Reset(f);
  WriteLn(FileSize(f));     // no. of records
  Seek(f, 2);               // go to record 2
  WriteLn(FilePos(f));      // current position
  CloseFile(f);
end.

FileSize() returns the number of records and FilePos() the current position. Seek(f, n) moves to record n (random access).

Command Line Parameters
var
  i: integer;

begin
  WriteLn('No. args: ', ParamCount);
  for i := 1 to ParamCount do
    WriteLn(ParamStr(i));
end.

ParamCount returns the number of command line arguments and ParamStr(i) each argument. ParamStr(0) is the name of the executable.

Classes e OOP


14 cards
Basic Class
type
  TPerson = class
    Name: string;
    Age: integer;
    procedure Introduce;
  end;

procedure TPerson.Introduce;
begin
  WriteLn(Name, ', ', Age);
end;

A class is declared with class and contains fields and methods. Methods are implemented outside with TPerson.Introduce. It is instantiated with Create.

Private and public
type
  TAccount = class
  private
    FBalance: real;  // hidden from outside
  public
    procedure Deposit(v: real);
    function Balance: real;
  end;

private restricts access to the inside of the class (encapsulation). public makes members accessible from outside. Private fields use the F prefix.

inherited
procedure TDog.Speak;
begin
  inherited Speak;  // calls the superclass one
  WriteLn('... and wags its tail');
end;

inherited calls the version of the method in the superclass. Useful for extending behavior instead of replacing it entirely.

Polymorphism
var
  shapes: array of TShape;
  f: TShape;
begin
  SetLength(shapes, 2);
  shapes[0] := TCircle.Create;
  shapes[1] := TSquare.Create;
  for f in shapes do
    WriteLn(f.Area);  // calls the right one
end.

With virtual/override methods, the same call (f.Area) runs the correct implementation according to the real type of the object at runtime.

Create and Free an Object
var
  p: TPerson;
begin
  p := TPerson.Create;
  try
    p.Name := 'Anna';
    p.Age := 30;
    p.Introduce;
  finally
    p.Free;  // release memory
  end;
end.

Objects are created with Create and must be released with Free. The try..finally guarantees the release even if an error occurs.

Properties
type
  TPerson = class
  private
    FName: string;
  public
    property Name: string read FName write FName;
    property ReadOnly: string read FName;
  end;

A property exposes fields with read and write, controlling access. It can be linked to getter/setter methods for validation.

is and the
var
  a: TAnimal;
begin
  a := TDog.Create;
  if a is TDog then
    WriteLn('is a dog');

  (a the TDog).Bark;
  a.Free;
end.

is checks the type at runtime and the does a safe cast (throws an exception if it fails). Essential for working with polymorphism.

for in (collections)
var
  list: TList<integer>;
  n: integer;
begin
  list := TList<integer>.Create;
  list.AddRange([1, 2, 3]);
  for n in list do
    WriteLn(n);
  list.Free;
end.

The for in iterates over collections and arrays cleanly, without indexes. It works with dynamic arrays, TList and other enumerables.

Constructor
type
  TPerson = class
    Name: string;
    constructor Create(n: string);
  end;

constructor TPerson.Create(n: string);
begin
  inherited Create;
  Name := n;
end;

var p: TPerson;
begin
  p := TPerson.Create('Anna');
end.

The constructor initializes the object on creation. inherited Create calls the base class constructor. It allows passing initial parameters.

Inheritance
type
  TAnimal = class
    procedure Speak; virtual;
  end;

  TDog = class(TAnimal)
    procedure Speak; override;
  end;

procedure TDog.Speak;
begin
  WriteLn('Woof woof!');
end;

Inheritance uses class(TAnimal). virtual marks the method the overridable and override reimplements it in the subclass (polymorphism).

Static Class and Self
type
  TCounter = class
    class var Total: integer;
    class procedure Increment;
  end;

class procedure TCounter.Increment;
begin
  Total := Total + 1;
end;

class members belong to the class and not the instance (shared). Self refers to the current object, like this in other languages.

Destructor
type
  TResource = class
    destructor Destroy; override;
  end;

destructor TResource.Destroy;
begin
  WriteLn('Releasing resources');
  inherited Destroy;
end;

The destructor Destroy (with override) runs when the object is released. It is used to clean up resources. It is called with Free, which checks for nil.

Abstract Methods
type
  TShape = class
    function Area: real; virtual; abstract;
  end;

  TCircle = class(TShape)
    Radius: real;
    function Area: real; override;
  end;

function TCircle.Area: real;
begin
  Result := 3.14159 * Radius * Radius;
end;

An abstract method is declared without implementation and forces subclasses to define it. It turns the base class into a contract (abstract class).

Interfaces
type
  ISavable = interface
    ['{GUID-HERE}']
    procedure Save;
  end;

  TDocument = class(TInterfacedObject, ISavable)
    procedure Save;
  end;

An interface defines a contract without implementation. The class inherits from TInterfacedObject and implements the methods. It supports reference counting.