Pascal — Reference
Source: https://www.freepascal.org/docs.html
Pascal
- Created: 1970 by Niklaus Wirth at ETH Zürich. Originally as a teaching language; Turbo Pascal (Borland, 1983) made it mainstream; Object Pascal / Delphi (Borland, 1995) industrialized it; Free Pascal Compiler (FPC) + Lazarus (open source) keep it alive today.
- Latest stable: Free Pascal 3.2.2 (released 2021-05-20). 3.2.4 release candidate June 2025; trunk dev
3.3.1. Embarcadero Delphi 12 Athens is the leading commercial Object Pascal IDE/compiler. - Paradigms: Imperative, procedural, modular, object-oriented (Object Pascal), generic, with structured exception handling and (in Delphi/Free Pascal) anonymous methods + closures.
- Typing: Strong, static, structural for arrays/records but nominal for declared types. Subrange types (
type Hour = 0..23;) are first-class. Strict by default; FPC’s mode switches relax some rules. - Memory: No GC for the compiler-managed code. Manual
New/Dispose, automatic stack for value types. Reference-counted for managed types (AnsiString/UnicodeString, dynamic arrays, interfaces).try..finallyfor deterministic cleanup; ARC mode optional in mobile/Linux Delphi (deprecated in newer versions). - Compilation: Ahead-of-time native code, no VM/runtime. Free Pascal Compiler (FPC): Linux/Win/macOS/BSD, ARM/AArch64/RISC-V/MIPS/AVR/PowerPC/SPARC/Z80, even WebAssembly + JVM backends. Embarcadero Delphi: Windows/macOS/iOS/Android/Linux x86_64. GNU Pascal (gpc) is unmaintained.
- Primary domains: Cross-platform desktop (Lazarus apps), embedded (FPC ARM/AVR), scientific/engineering, retail point-of-sale (legacy Delphi), older Windows business apps, education.
- Official docs: https://www.freepascal.org/docs.html (FPC), https://wiki.lazarus.freepascal.org/ (Lazarus IDE), https://docwiki.embarcadero.com/RADStudio/ (Delphi).
At a glance
Pascal split into two living branches: standardized Pascal (ISO 7185:1990 / ISO 10206 Extended Pascal — both effectively dead in industry but supported in mode iso for academic work) and Object Pascal, which is what people use. Object Pascal is what runs in Delphi and what FPC’s default mode objfpc and mode delphi accept. The FPC + Lazarus stack delivers a true write-once compile-everywhere native desktop GUI experience that’s hard to match — one Lazarus codebase compiles to Win32/Win64, Linux GTK/Qt, macOS Cocoa, and ARM with no source changes for typical CRUD apps.
Getting started
Install FPC + Lazarus:
- Easy path: install Lazarus which bundles FPC. Windows: installer from https://www.lazarus-ide.org/. macOS:
brew install --cask lazarusor DMG. Linux:sudo apt install lazarus(often older; better to use fpcupdeluxe). - fpcupdeluxe: GUI tool to install/maintain multiple FPC + Lazarus versions side-by-side; the de-facto version manager. https://github.com/LongDirtyAnimAlf/fpcupdeluxe.
- Just FPC:
sudo apt install fpcthenfpc --version.
Hello world (hello.pas):
program Hello;
{$mode objfpc}{$H+}
begin
WriteLn('Hello, world!');
end.{$mode objfpc}selects Free Pascal’s Object Pascal dialect; alternatives:delphi,tp(Turbo Pascal 7),iso,mac,extpas(ISO Extended Pascal).{$H+}makesstringmap toAnsiString/UnicodeStringinstead of fixedShortString.
Compile + run: fpc hello.pas && ./hello (Unix) or fpc hello.pas && hello.exe (Windows).
Project layout (Lazarus app):
myapp/
myapp.lpi -- Lazarus project info (XML)
myapp.lpr -- main program file
unit1.pas -- form unit (code)
unit1.lfm -- form layout (Lazarus Form Module)
Lazarus generates and manages .lpi/.lfm. Build via IDE or lazbuild myapp.lpi.
Package/build tool. fpmake (Pascal-based, like Rake) — declarative build via fpmake.pp. fppkg for online package fetching (https://gitlab.com/freepascal.org/fpc/source). For Lazarus, OPM (Online Package Manager) ships in the IDE; many community packages on https://wiki.lazarus.freepascal.org/Online_Package_Manager.
REPL. None native. Some workaround tools (e.g. InstantFPC lets you run .pas files like scripts: instantfpc script.pas).
Basics
Types & literals. Numbers: Integer (native size: 32 or 64), Int8/Int16/Int32/Int64/UInt8…UInt64, Single (32-bit float), Double (64-bit), Extended (80-bit on x86). Booleans: Boolean/ByteBool/WordBool. Characters: Char (8-bit AnsiChar), WideChar (UTF-16 unit), UnicodeChar. Strings: ShortString (max 255 bytes, length in byte 0), AnsiString (heap, ref-counted, code-page aware), UnicodeString (heap, ref-counted, UTF-16), WideString (Windows BSTR). Literals: 42, $FF (hex), &777 (octal), %1010 (binary), 1.0e10, 'hello', #13#10 (concatenated char literals = CRLF).
Variables/scoping. Declared in var blocks, scoped to the enclosing routine/unit. Constants: const Pi = 3.14; (typed: const X: Integer = 5;). Subrange types: type Hour = 0..23;. Enums: type Color = (Red, Green, Blue); — first-class with Ord(Red) = 0, Inc(C), etc.
Control flow. if cond then ... else ...;, case x of 1: ...; 2,3: ...; else ... end;, while cond do ...;, repeat ... until cond;, for i := 1 to N do ...; / for i := N downto 1 do ...;, for x in collection do ...; (since FPC 2.4 / Delphi 2005). break;, continue;, exit; (from procedure), exit(value); (return from function, Delphi-style).
Procedures & functions. procedure P(A: Integer; var B: string); and function F(X: Integer): Integer;. Parameter modes: by-value (default), var (by-reference, mutable), const (by-reference, read-only — compiler may inline), out (write-only, no init). Function result via Result := value; (mode objfpc/delphi) or F := value; (classic). Default parameter values: procedure P(A: Integer = 0);. Overloading: mark with overload directive.
Strings. Three live string types: ShortString (legacy, fixed max 255), AnsiString (preferred for byte strings), UnicodeString (preferred for text — UTF-16 internally, default string in Delphi 2009+). Length(s), Copy(s, start, len), Pos(sub, s), s := 'a' + 'b';. Indexing is 1-based: s[1] is the first char. With {$H+} directive, string is AnsiString/UnicodeString per platform default.
Collections. Static arrays: var A: array[1..10] of Integer;. Dynamic arrays: var A: array of Integer; SetLength(A, 100); — heap-allocated, ref-counted, 0-indexed (A[0] … A[99]). Records: type TPoint = record X, Y: Integer; end;. Variant records (tagged unions): record case Tag: Integer of 0: (Int: Integer); 1: (Str: ShortString); end;. Sets: type TFlags = set of (fA, fB, fC);, then s := [fA, fC]; if fA in s then .... Generic containers (since 2009-ish): TList<T>, TDictionary<K,V> from Generics.Collections.
Intermediate
Type system depth. Object Pascal classes (type TFoo = class ... end) are heap-allocated, single-inheritance, with multiple-inheritance-of-interface via IFoo = interface. Methods marked virtual are dispatched dynamically; override with override; mark final with final. Properties with read/write accessors: property Count: Integer read FCount write SetCount;. Class methods (callable on the class itself): class procedure CreateAll;. Class variables (shared): class var FInstance: TFoo;. Generics (Delphi 2009+, FPC 2.4+): type TList<T> = class ... end;. Anonymous methods + closures: var Add: TFunc<Integer, Integer> := function(X: Integer): Integer begin Result := X + 1; end; (Delphi 2009+, FPC has {$modeswitch functionreferences}).
Modules. Units are the modularity primitive. Each .pas is a unit:
unit MyUnit;
interface
uses OtherUnit;
type TFoo = class ... end;
procedure DoSomething;
implementation
uses HelperUnit;
procedure DoSomething; begin ... end;
initialization
// run at program start in dependency order
finalization
// run at program shutdown in reverse order
end.The interface section is the public API; implementation is private. initialization/finalization blocks let units do startup/shutdown work safely.
Error handling. Structured exceptions: try ... except on E: Exception do ... end; and try ... finally ... end;. Hierarchy rooted at Exception. raise EMyError.Create('msg');. raise; (bare) re-raises. Standard exceptions in SysUtils.
Concurrency primitives. TThread class wraps OS threads (Execute method overrides). Synchronization: TCriticalSection, TRTLCriticalSection, TMonitor (Delphi-style, Monitor.Enter(obj)), TMultiReadExclusiveWriteSynchronizer. TThreadPool for work queues. Parallel Programming Library (PPL) in Delphi: TParallel.&For, TTask.Run. Async/Await in modern Delphi via PPL futures. FPC has MTProcs for OpenMP-like parallel loops. Atomic ops in SyncObjs (InterlockedIncrement).
I/O. Classic Pascal: Assign(F, 'name'); Reset(F); ReadLn(F, x); CloseFile(F);. Modern: TFileStream, TStringList.LoadFromFile, TStreamReader. The VCL (Delphi) and LCL (Lazarus) provide TFile/TPath/TDirectory (Delphi IOUtils). Network: Indy (IdHTTP, IdTCPClient), Synapse, lNet. JSON: JsonTools, fpjson, System.JSON.
Stdlib highlights. RTL (Run-Time Library): SysUtils (strings, dates, files, exceptions), Classes (TStringList, TStream, TList, TComponent), Math, DateUtils, StrUtils, Variants, TypInfo (RTTI), Generics.Collections. FCL (Free Component Library): fpjson, fpxml, database connectors, web (fphttpserver), images. LCL (Lazarus Component Library): widget set abstraction (GTK2/3, Qt5/6, Cocoa, Win32, Carbon).
Advanced
Memory model. Class instances are heap pointers under the hood; var f: TFoo; is a reference, f := TFoo.Create; allocates, f.Free; deallocates (idiomatic: try ... finally f.Free; end; or FreeAndNil(f)). Records are value types, copied on assignment. Strings, dynamic arrays, interfaces are reference-counted with copy-on-write — assigning is cheap, mutating triggers a copy if refcount > 1. GetMem/FreeMem for raw heap. Custom memory managers via SetMemoryManager (you can swap in FastMM5, NexusMM, ScaleMM for performance).
Concurrency deep dive. TThread is the building block; you almost always wrap with a queue/pool. TThread.Synchronize and TThread.Queue marshal back to the main thread for GUI updates (this is mandatory — VCL/LCL are not thread-safe). PPL (TTask.Future, TTask.WaitForAll) is the modern Delphi pattern. MTProcs (FPC) for ProcThreadPool.DoParallelLocalProc. Anonymous threads via TThread.CreateAnonymousThread(procedure begin ... end).Start;. Lock-free atomics in SyncObjs. No language-level async/await — closures + futures are how it’s done.
FFI. Direct C interop via external directive:
function strlen(s: PChar): NativeUInt; cdecl; external 'libc' name 'strlen';Calling conventions: cdecl, stdcall, register (FPC default — fastcall-like), pascal, safecall, ms_abi_default. Pointers: PInteger, PChar, Pointer, ^Integer. C strings: PAnsiChar/PWideChar. Header translation tools: h2pas, C-to-Pascal converters. COM/ActiveX on Windows via interfaces with {$M+} and IDispatch. Java/Android via JNI bindings (FPC’s Android target).
Reflection (RTTI). TypInfo unit + Rtti.pas (Delphi 2010+ / FPC 3.0+) provides TRttiContext, TRttiType, TRttiMethod, TRttiProperty — full enumeration and invocation. Compile classes with {$M+} (or inherit from TPersistent) to get extended RTTI. Used by JSON serializers, ORM (mORMot, TMS Aurelius), DI containers.
Performance tools. AQTime (commercial), Sampling Profiler (free, Delphi), valgrind/callgrind on Linux FPC binaries, perf for native, VTune if you go x86. FastMM4/5 for memory leak detection (replace memory manager, get full leak reports at shutdown). Lazarus IDE has built-in heap-trc backed leak reporting (-gh switch).
God mode
Object Pascal class system. Every class descends from TObject (RTL) or TInterfacedObject (for ref-counted COM-style objects). Class-of types: class of TFoo is a metaclass — var C: TPersistentClass; C := TStringList; obj := C.Create; lets you instantiate by class reference. Used heavily in VCL’s component streaming (form files store class names, IDE resolves via class registry).
Properties + RTTI + streaming. A published property is enumerable via RTTI. TStream.WriteComponent serializes any TComponent by walking published properties — that’s how .dfm/.lfm form files work. You can write custom property editors that hook the IDE.
Inline assembly. Both FPC and Delphi support asm ... end; blocks with platform-specific assembly:
function Add(a, b: Integer): Integer; assembler;
asm
mov eax, a
add eax, b
end;Useful for SIMD intrinsics that the compiler hasn’t wrapped, or hand-tuned hot paths. FPC supports AT&T syntax via {$asmmode att}.
{$mode} and {$modeswitch} directives. {$mode delphi} enables Delphi-compatibility (operator overloading semantics, Result, exceptions on/off, etc.); {$mode objfpc} is FPC’s preferred Object Pascal mode. Modeswitches layer features: {$modeswitch advancedrecords} lets records have methods + properties; {$modeswitch functionreferences} enables anonymous-method types; {$modeswitch nestedprocvars} allows nested-procedure variables. Pin them at the top of every .pas you write.
Cross-compilation. FPC’s killer feature. fpc -Tlinux -Parm -CpARMV7A myapp.pas compiles a Linux ARM binary on a Windows x86_64 host (you need the matching cross-binutils). Targets include AVR microcontrollers, RISC-V, embedded ARM Cortex-M (with no OS), WebAssembly (-Twasi/-Twasm32), JVM bytecode (limited). fpcupdeluxe automates installing cross-toolchains.
Lazarus + LCL widgetset abstraction. TForm, TButton, etc. are interfaces; the LCL has multiple widgetset backends (win32, gtk2, gtk3, qt5, qt6, cocoa, carbon, customdrawn). Same source, recompile for the target widgetset. Performance is native (no Electron tax). Conditional defines ({$IFDEF LCLGTK2}) for backend-specific tweaks.
Custom packages with FPMake. fpmake.pp is a Pascal program that constructs a build description. Compile it (fpc fpmake.pp), run ./fpmake build install. Integrates with fppkg for installing/distributing packages from the central repo.
Delphi-specific god-mode. FireMonkey (FMX) GPU-accelerated cross-platform UI; LiveBindings expression engine; RTTI-driven property serialization; the form designer is itself a Pascal program editing other Pascal programs. {$EXTERNALSYM} and {$HPPEMIT} directives generate matching C++ headers for C++Builder consumption.
Idioms & style
- Pin your
{$mode}and{$H+}at the top of every unit. Mode determines language semantics; rely on no defaults. - Naming: Types prefixed with
T(TPoint,TStringList); interfaces withI(IDisposable); pointers withP(PInteger). Methods/identifiers inPascalCase. Field names start withF(FCount). Enum members get a 2-letter prefix tied to the type (fkBold,fkItalicfor aTFontKind). try ... finally Free; end;around every manually-allocated object — non-negotiable.FreeAndNil(obj)instead ofobj.Freewhen the reference might be re-checked.- Strings are 1-indexed (
s[1]is first char), dynamic arrays are 0-indexed (a[0]). Yes, both. Don’t slip up. - Use
constfor read-only reference parameters (const s: string) — avoids refcount churn. - Formatter/linter: JCF (Jedi Code Format) — built into Lazarus IDE. PtopX (older). Delphi has Delphi Formatter in the IDE. PasPascal + PascalAnalyzer for static analysis. ptop is FPC’s own pretty-printer.
- Expert review focus: (1) Every
Createpaired with aFreeintry..finally? (2) String types consistent ({$H+}set; not mixingShortStringandAnsiString)? (3) Ref-counted leaks via interface-circular references? (4) Thread access toTStringList/VCL/LCL only viaSynchronize/Queue? (5){$mode}and{$modeswitch}declared per file — no implicit defaults? (6)class procedure Free;not called on anilinstance (yes,nil.Freeis a no-op in Object Pascal — surprisingly safe)? (7) Pointer arithmetic only with{$POINTERMATH ON}?
Ecosystem
- GUI frameworks: VCL (Delphi, Windows-only — the classic), FMX/FireMonkey (Delphi, cross-platform GPU UI), LCL (Lazarus, cross-platform native widget abstraction).
- Web: Brook, mORMot 2 (also a full SOA / ORM / database stack), Pas2JS (Pascal-to-JavaScript transpiler), fphttpserver (FCL).
- Database: mORMot 2, TMS Aurelius (ORM), ZeosLib (multi-DB), SQLdb (FCL), FireDAC (Delphi).
- Game dev: Castle Game Engine (3D, Pascal-native), SDL bindings.
- Embedded: mikroPascal (commercial, MCU-focused), FPC AVR/ARM (open source, bare-metal). Lazarus/FPC build firmware for STM32, ESP32 (limited), AVR.
- Testing: fpcunit (xUnit-style, ships with FPC), DUnit / DUnitX (Delphi).
- Notable users: Skype (original Windows client was Delphi), Total Commander, Inno Setup (the installer maker — itself in Object Pascal), Beyond Compare, Embarcadero Delphi IDE itself (Delphi is written in Delphi), Lazarus IDE (in Lazarus/FPC), WinRAR’s GUI, R Studio Data Recovery, much enterprise CRUD in finance/insurance.
Gotchas
stringtype changes meaning by mode + directive. With{$H+}it’sAnsiStringorUnicodeStringdepending on platform/dialect; without, it’sShortString(max 255 bytes). Mixed code corrupts data. Pin{$H+}everywhere.- String indexing is 1-based; dynamic array indexing is 0-based. Mixing them up is the #1 off-by-one source.
AnsiStringis platform-dependent UTF-8 in Lazarus, system codepage in Delphi. Cross-platform code should preferUnicodeString(UTF-16) or explicitly UTF-8 (UTF8String).- No null-safety. A
TFooreference can benil; calling a method onnilfaults.nil.Freeis the lone exception (safe by design inTObject.Free). - Global
vars in units initialize in dependency order (peruses), but circularusesare detected only betweeninterfacesections. Move circular dependencies toimplementationuses. varparameter sharing. Passing the same variable to twovarparameters of one call is undefined. Compiler doesn’t always warn.- Operator overloading semantics differ between modes.
mode delphiuses class operators;mode objfpcuses unit-leveloperatordeclarations. Code isn’t portable across modes without rewriting. TStringList.Sorted := True;silently sorts in place but also changes lookup semantics to binary search. Setting back toFalsedoesn’t restore order. Hot bug source.- Reference cycles in interfaces.
IFooref-counts; two interfaces holding each other never get freed. Break cycles with weak references ([weak]attribute, Delphi mobile/Linux only) orPointercasts manually. - Form files (
.dfm/.lfm) and class names must match. Renaming a form class without re-saving the form file breaks loading at runtime, not compile time. Resultshadows localResultonly inmode delphi/objfpc. In classic Pascal, you assign to the function name (MyFunc := value). Mixing styles is confusing.
Citations
- Free Pascal documentation portal: https://www.freepascal.org/docs.html.
- Free Pascal Compiler 3.2.2 release (2021-05-20): https://www.freepascal.org/news.html.
- Wikipedia, Free Pascal (versions, targets, modes): https://en.wikipedia.org/wiki/Free_Pascal.
- Lazarus IDE wiki: https://wiki.lazarus.freepascal.org/.
- Embarcadero Delphi DocWiki: https://docwiki.embarcadero.com/RADStudio/.
- Delphi Object Pascal Style Guide: https://docwiki.embarcadero.com/RADStudio/en/Object_Pascal_Style_Guide.
- ISO 7185:1990 (Standard Pascal): https://www.iso.org/standard/13802.html.
- ISO 10206:1990 (Extended Pascal): https://www.iso.org/standard/18237.html.
- mORMot 2 (full Object Pascal SOA stack): https://github.com/synopse/mORMot2.
- Castle Game Engine: https://castle-engine.io/.
- fpcupdeluxe (version manager): https://github.com/LongDirtyAnimAlf/fpcupdeluxe.