Object Pascal
Object Pascal is an object-oriented extension of the Pascal programming language, incorporating support for classes, methods, inheritance, and other paradigms to enable structured and modular software development.[1][2]
Originally developed in the early 1980s at Apple Computer by Larry Tesler in collaboration with Niklaus Wirth, it began as Clascal for the Lisa Workshop system and evolved into Macintosh Pascal, marking one of the first implementations of object-oriented features in a Pascal dialect.[1]
In the late 1980s, Anders Hejlsberg integrated Object Pascal elements into Turbo Pascal at Borland, enhancing its capabilities for MS-DOS and laying the groundwork for professional development tools.[3][4]
Borland's 1995 release of Delphi popularized Object Pascal as a rapid application development (RAD) language, featuring visual design tools and cross-platform support through native compilers for Windows, macOS, Linux, iOS, and Android.[4][5]
Key features include strong static typing inherited from Pascal, along with advanced OOP constructs like properties, interfaces, generics, and anonymous methods, which facilitate robust, type-safe code for enterprise and desktop applications.[1][2]
Open-source implementations such as Free Pascal, started in 1993, extend Object Pascal compatibility across multiple platforms and architectures, supporting modes that align with Delphi syntax for portability.[1][6]
As of 2025, Object Pascal remains actively maintained, with Embarcadero's RAD Studio providing the latest enhancements in versions like Delphi 13 Florence, emphasizing modern language constructs for high-performance software.[2][7]
History
Origins in Standard Pascal
Object Pascal traces its roots to Standard Pascal, a programming language designed by Niklaus Wirth at the Swiss Federal Institute of Technology (ETH Zurich) in 1970 as a tool for teaching structured programming principles.[8] Wirth aimed to create a small, efficient language that encouraged clear, readable code while addressing limitations in earlier languages like ALGOL 60, with the first compiler becoming operational in early 1970 and the formal definition published shortly thereafter.[9][10]
Standard Pascal emphasized structured programming through key features such as strong static typing, which enforced type declarations for variables and prevented implicit conversions to reduce errors; block structure, allowing nested scopes for procedures and functions; and support for modular code organization via separate procedures and functions without built-in support for object-oriented paradigms like classes or inheritance.[11][10] These elements promoted disciplined programming practices, including the use of control structures like if-then-else and while-do loops, but the language remained procedural and lacked direct mechanisms for data abstraction beyond records and pointers.[8][9]
An early extension that advanced Pascal's portability and modularity was UCSD Pascal, developed at the University of California, San Diego, starting in late 1974 and first released in 1978 under the direction of Professor Kenneth Bowles.[12] This implementation introduced a p-code interpreter, compiling Pascal source to an intermediate pseudo-code that could run on a virtual machine, enabling the system to operate across diverse hardware like the Intel 8080 and Zilog Z80 without native recompilation.[12] UCSD Pascal also incorporated enhanced modular concepts, such as improved file handling and separate compilation units, laying groundwork for more flexible software environments while remaining faithful to Standard Pascal's core syntax.
The transition toward object-oriented ideas in the late 1970s and 1980s built on these foundations, with Wirth's Modula-2, specified in 1978 at ETH Zurich, serving as a key precursor to Object Pascal.[13] Modula-2 extended Pascal by introducing modules—self-contained units that encapsulated definitions and implementations for better information hiding and separate compilation—but offered only limited object-oriented features, such as procedure types and low-level concurrency via coroutines, without full inheritance or polymorphism.[13] This design emphasized modular system construction for larger programs, influencing subsequent efforts to integrate true object-oriented capabilities into Pascal derivatives.[14]
Apple's Object Extensions
Apple Pascal, introduced in the early 1980s, served as Apple's implementation of UCSD Pascal tailored for the Macintosh platform, building on the p-System architecture originally developed at the University of California, San Diego. This version extended the procedural foundations of Standard Pascal with enhancements for the Macintosh's graphical user interface and resource management, enabling developers to interface directly with the Macintosh Toolbox for event handling and window management.[15][16]
In 1983, Apple developed Clascal as an object-oriented extension to Lisa Pascal, which itself derived from UCSD Pascal and was used on the Apple Lisa computer. Clascal introduced key object-oriented features such as class declarations, methods, and single inheritance, allowing programmers to define object types with encapsulated data and behaviors. These additions were influenced by Smalltalk and consulted with Pascal's creator, Niklaus Wirth, marking an early effort to blend procedural and object-oriented paradigms within Pascal's syntax.[17][3][18]
Clascal's innovations included object types that could inherit from parent classes, virtual methods for runtime polymorphism, and seamless integration with the Macintosh Toolbox through object wrappers for system resources like menus and dialogs. This facilitated rapid development of GUI applications by treating Toolbox elements as inheritable objects, reducing boilerplate code and promoting code reuse. For instance, developers could subclass a base window object to customize behavior without directly manipulating low-level procedure calls.[17]
By 1986, Apple refined these concepts into Object Pascal, documented in the MPW Pascal Reference, which became the primary language for the MacApp application framework. Object Pascal expanded Clascal's features with improved type safety, dynamic binding, and support for the Macintosh Programmer's Workshop (MPW) environment, enabling the creation of large-scale, maintainable applications through MacApp's class hierarchy. This version emphasized virtual methods and inheritance hierarchies that mirrored the Macintosh's event-driven model, powering early Macintosh software development until the late 1980s.[19][16]
Apple's adoption of Object Pascal waned in the early 1990s as the company shifted toward C++ for systems programming, particularly with the release of System 7 in 1991 and MacApp 3.0, which transitioned to C++ to support broader performance needs and emerging standards. This decline reflected evolving industry trends toward multi-paradigm languages, though Object Pascal's foundational contributions influenced subsequent Pascal dialects.[16][15]
Borland's Commercialization
Borland International introduced Turbo Pascal in November 1983 as an integrated development environment (IDE) and compiler for the Pascal programming language, targeting MS-DOS systems and emphasizing rapid compilation and ease of use.[20] This product quickly gained popularity among developers due to its affordability and performance, shipping initially on November 20, 1983, via mail-order advertisements in magazines like Byte.[21] Turbo Pascal's success laid the foundation for Borland's dominance in the Pascal ecosystem, evolving from a basic compiler to a full-featured toolset that supported modular programming through units.
Initial support for object-oriented programming (OOP) arrived in Turbo Pascal 5.5, released on May 2, 1989, which extended the language with object types that combined data fields and procedures, enabling encapsulation and basic polymorphism through pointers to dynamic objects.[22] These features drew inspiration from Apple's earlier Object Pascal extensions but adapted them for broader commercial use, allowing static and dynamic object allocation while maintaining backward compatibility with standard Pascal.[23]
Turbo Pascal 7.0, released in 1992, marked a significant evolution toward what became known as Object Pascal by enhancing OOP capabilities with full inheritance, virtual and dynamic methods for runtime polymorphism, and constructors/destructors for object lifecycle management.[24] Object types in this version supported transitive inheritance (e.g., via syntax like TPoint = object(TLocation)), late binding through virtual method tables (VMTs), and the inherited keyword for method overriding, forming a robust foundation for object-based programming without yet introducing reference-based classes.[24] These additions positioned Turbo Pascal as a professional tool, with Borland also offering a higher-end Borland Pascal variant oriented toward enterprise development.
In 1995, Borland launched Delphi 1 on February 14, revolutionizing Object Pascal commercialization by introducing a visual RAD (rapid application development) IDE for 16-bit Windows 3.1, tightly integrated with the Visual Component Library (VCL) framework.[25] Delphi extended the language with classes as reference types (contrasting TP7's value-based objects), read/write properties for controlled data access, and visual form designers that enabled drag-and-drop component placement, significantly accelerating Windows application development.[26] The VCL provided reusable components for UI elements like forms and buttons, leveraging Object Pascal's type safety and OOP features to streamline database connectivity via tools like the Borland Database Engine (BDE).
Borland underwent several corporate transformations that impacted Object Pascal's trajectory. In 1999, amid a strategic shift toward enterprise software, the company rebranded as Inprise Corporation to reflect its focus on middleware and services.[27] By 2006, facing financial pressures, Borland spun off its developer tools division—including Delphi—into a subsidiary called CodeGear on November 14, establishing it as an independent entity responsible for language and IDE evolution.[28] In 2008, Embarcadero Technologies acquired CodeGear for $23 million, retaining the division and continuing Delphi's development under its umbrella, which ensured ongoing investment in Object Pascal tools.[28]
Key releases under these entities advanced Object Pascal's capabilities for modern platforms. Delphi 2009 introduced comprehensive Unicode support across the runtime library (RTL), IDE, and VCL, enabling native handling of international characters and strings via the UnicodeString type, which became the default for text operations.[29] The XE series, starting with XE in 2010 and extending through XE7 in 2014, added cross-platform mobile development, including support for Android and iOS via the FireMonkey (FMX) framework, with new components for touch interfaces, REST clients, and push notifications to target smartphones and tablets.[30] These enhancements solidified Object Pascal's role in commercial software production, bridging desktop and mobile paradigms.
Open-Source and Modern Eras
The open-source revival of Object Pascal began in the early 1990s with the launch of the Free Pascal Compiler (FPC) project in 1993, initiated by Florian Klämpfl as a multi-platform alternative to proprietary Pascal implementations. FPC is a free and open-source compiler that supports various dialects of Pascal and Object Pascal, targeting numerous processor architectures including x86, ARM, and PowerPC, as well as operating systems such as Windows, Linux, macOS, and embedded systems. Released under the GPL and LGPL licenses, it emphasizes compatibility with Turbo Pascal, Delphi, and ISO standards, enabling developers to create cross-platform applications without vendor lock-in.[31]
Building on FPC, the Lazarus integrated development environment (IDE) emerged in 1999 as a free, open-source counterpart to Borland's Delphi, providing rapid application development (RAD) tools with visual form designers and component libraries. Lazarus leverages FPC as its backend compiler, supporting cross-platform GUI applications through the LCL (Lazarus Component Library), which mimics the Visual Component Library (VCL) of Delphi while adapting to native widgets on different platforms. This project has fostered a vibrant community, contributing to ongoing enhancements in language support and tooling.
In parallel, commercial evolution continued under Embarcadero Technologies, which acquired Delphi from Borland in 2008 and released modern versions emphasizing multi-platform capabilities. Delphi 10.4 Sydney, launched in May 2020, introduced improved code insights, unified memory management, and enhanced support for high-DPI displays across Windows, macOS, iOS, and Android targets. Subsequent updates included Delphi 11 Alexandria in September 2021, adding Linux server-side development support via the Community Edition and expanded Android deployment options, including compatibility with Android 11 and later; Delphi 12 Athens in November 2023, which brought support for Android 14, iOS 17, macOS Sonoma, and LLVM-based compilation for Linux; and Delphi 13 Florence in September 2025, featuring a 64-bit IDE, the ternary operator in Object Pascal, and further performance optimizations to address enterprise and mobile needs in the 2020s.[32][33][34][35] These releases integrate Object Pascal with contemporary frameworks, facilitating web and mobile integration through FireUI and REST components.
Other notable projects have extended Object Pascal for diverse targets, such as Oxygene, developed by RemObjects Software starting in 2005 as a modern dialect for cross-compilation to .NET, Java, and other platforms. Originally named Chrome, Oxygene integrates with Visual Studio and supports full .NET Framework features, later expanding to Java (via Cooper in 2011) and enabling seamless porting of Object Pascal code to non-native environments without runtime dependencies. Complementing this, Smart Mobile Studio, introduced around 2010, offers Smart Pascal—a Delphi-compatible dialect that compiles to JavaScript and HTML5 for web applications, bridging Object Pascal to browser-based development.[3]
Community-driven standardization efforts have also advanced in the modern era, with proposals for extending ISO Pascal standards to incorporate full object-oriented features, building on the 1990 Extended Pascal (ISO 10206) specification. Free Pascal, for instance, implements these extensions, including modules, generics, and runtime type information, while ongoing discussions in developer forums and ISO working groups aim to unify dialects for better interoperability. In the 2020s, these efforts have supported growing integration with web technologies via JavaScript transpilers and mobile platforms through native API bindings in tools like Delphi and Lazarus.[36]
Language Features
Core Syntax and Types
Object Pascal programs follow a structured format beginning with an optional program declaration, followed by a main block enclosed in begin and end keywords, with statements separated by semicolons. The basic syntax is program ProgramName; begin Statement1; Statement2; ... end., where the program name is optional in some implementations but recommended for clarity. This structure inherits from Standard Pascal but supports extensions for modern use. Semicolons serve as terminators rather than separators in some contexts, allowing optional omission before end or else.
As of Delphi 13 (2025), Object Pascal includes a ternary conditional operator for concise expressions: Condition if TrueExpr else FalseExpr;, which evaluates to TrueExpr if Condition is true, otherwise FalseExpr. This matches the semantics of the C ternary operator and can be used in assignments or as part of larger expressions.[37]
Data types in Object Pascal are strongly typed, requiring explicit declarations for variables. Integer types include Integer, a signed 32-bit type with range -2,147,483,648 to 2,147,483,647 on most platforms, and Int64, a signed 64-bit type ranging from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807. Real types encompass Real, an alias for platform-dependent floating-point (often 32-bit single precision), and Double, a 64-bit double-precision type with approximately 15 decimal digits of precision. Strings are handled via String, which in modern implementations like Delphi is a managed Unicode string type with dynamic length up to 2 GB, while Boolean is an ordinal type with values True (1) and False (0). Variable declarations use the syntax var VariableName: Type;, ensuring type safety at compile time.
Control flow constructs provide procedural logic. Conditional statements use if Condition then Statement else Statement;, where Condition evaluates to Boolean, supporting nested and compound statements. As of Delphi 13 (2025), new operators is not and not in are available for negated type and set membership checks, enhancing expressiveness in conditions. The case statement selects based on an ordinal expression: case Expression of Value1: Statements; Value2: Statements; ... else Statements; end;, allowing multiple values per case with commas. As of Delphi 13 (2025), string types are supported as case selectors in Delphi, expanding applicability beyond ordinals. Loops include for Variable := Initial to Final do Statement; for ascending iteration (or downto for descending), while Condition do Statement; for pre-tested loops, and repeat Statement until Condition; for post-tested loops that execute at least once. These structures enforce structured programming principles without goto reliance.
Procedures and functions encapsulate reusable code blocks. A procedure is declared as procedure ProcedureName(Parameters); begin Statements; end;, performing actions without return value, while a function uses function FunctionName(Parameters): ReturnType; begin Statements; Result := Value; end;, requiring a Result assignment for the return. As of Delphi 13 (2025), the noreturn directive can be applied to procedures to indicate they do not return, aiding compiler optimizations and analysis. Parameters support modes: value parameters pass by copy (Param: Type), var for pass-by-reference modification, const for read-only efficiency, and out for output-only initialization. Overloading allows multiple routines with the same name but differing parameter types or counts, resolved at compile time for code reuse.[38]
Arrays and records enable composite data handling. Static arrays are declared as var Arr: array[Low..High] of ElementType;, with fixed bounds like array[1..10] of [Integer](/page/Integer);, while dynamic arrays use array of ElementType, resized at runtime via SetLength(Arr, Size);. Records group heterogeneous fields: type RecType = [record](/page/Record) Field1: Type1; Field2: Type2; end; var R: RecType;, accessed as R.Field1. Packed records, declared with the packed keyword (packed [record](/page/Record) ... end;), minimize memory by aligning fields tightly, useful for interfacing with hardware or legacy data where each field occupies exactly its size without padding. These types support nested structures for complex data modeling.
Object-Oriented Programming
Object Pascal supports object-oriented programming through classes, which encapsulate data and behavior, enabling inheritance, polymorphism, and encapsulation. Classes are reference types that inherit from a root class, typically TObject, providing foundational methods like construction and destruction. This paradigm extends the procedural roots of Pascal by allowing developers to model real-world entities with structured hierarchies and dynamic behavior.[39]
Classes in Object Pascal are declared using the class keyword within a type declaration, specifying visibility sections for fields and methods to control access. Fields, which store data, are declared with visibility modifiers such as private, protected, public, or published, followed by the field name and type; for example, private FValue: Integer;. Methods are procedures or functions defined similarly, with parameters and return types as needed; public procedure Process; or function Calculate: Real;. Constructors initialize instances and are declared as constructor Create(AParam: Type); virtual;, often calling inherited constructors to handle ancestor fields. Destructors clean up resources and follow the syntax destructor Destroy; override;, typically invoked automatically via the Free method on TObject. As of Delphi 13 (2025), the NameOf intrinsic function provides the compile-time name of identifiers like properties or methods as strings, useful for reflection and debugging.[39]
Inheritance allows a derived class to extend an ancestor class, reusing and modifying its members while adding new ones. The syntax specifies the ancestor in parentheses after the class keyword: type TDerived = class(TAncestor). Derived classes inherit all non-private members and can override virtual or dynamic methods using the override directive to customize behavior, such as redefining a virtual procedure Process; in the child class. This promotes code reuse and hierarchical organization without duplicating declarations.[40][41]
To simulate multiple inheritance, Object Pascal uses interfaces, which define contracts of methods and properties without implementation. An interface is declared as type IMyInterface = interface(IInterface) ['{GUID}'] procedure DoAction; end;, inheriting from IInterface for reference counting and including a globally unique identifier for compatibility, such as with COM. Classes implement interfaces by listing them after the ancestor class, using a comma: TMyClass = class(TInterfacedObject, IMyInterface), and must provide concrete implementations for all members. This enables a single class to conform to multiple interfaces, achieving polymorphism across unrelated hierarchies.[42]
Properties provide controlled access to class fields, enhancing encapsulation by hiding internal storage while exposing getter and setter logic. Declared in the public section, the basic syntax is property Name: Type read Getter write Setter;, where Getter is a field or parameterless method returning the type, and Setter is a procedure accepting a value of that type; for instance, property Value: Integer read FValue write SetValue;. Indexed properties extend this for array-like access: property Items[Index: Integer]: Type read GetItem write SetItem;, allowing indexed reads and writes via methods that take the index parameter. This mechanism supports read-only, write-only, or default properties, abstracting data manipulation without direct field exposure.[43]
Polymorphism in Object Pascal is achieved through virtual and abstract methods, enabling dynamic binding where the method invoked depends on the object's actual type at runtime rather than its declared type. Methods marked virtual; support overriding in descendants, with the override; directive ensuring correct binding; abstract methods, declared as virtual; abstract;, require implementation in non-abstract descendants and cannot be called directly in the declaring class. Dynamic methods, using the dynamic; directive, offer similar runtime dispatch but optimize for scenarios with infrequent overrides by reducing vtable size. Compiler directives like $IFDEF can conditionally enable features, but core polymorphism relies on these directives for flexible, type-safe behavior.[41]
Units and Modules
In Object Pascal, units serve as the primary mechanism for modularizing code, enabling reusability, organization, and namespacing across programs and libraries. A unit is a self-contained source file that encapsulates declarations and implementations, allowing developers to separate public interfaces from private details while promoting code sharing without tight coupling. This modularity contrasts with standard Pascal's simpler program files, where all code was typically contained in a single file lacking built-in separation of concerns; Object Pascal's units extend this by supporting advanced features like dynamic linking and object-oriented constructs within modular boundaries.[44][45]
The structure of a unit begins with a declaration using the unit keyword followed by the unit name, such as unit MyUnit;. This is followed by an optional interface section, which defines the public API visible to other units or programs, including types, variables, constants, and procedure/function declarations. For example:
unit MyUnit;
interface
type
TMyType = [class](/page/Class)
procedure DoSomething;
end;
var
MyVar: [Integer](/page/Integer);
unit MyUnit;
interface
type
TMyType = [class](/page/Class)
procedure DoSomething;
end;
var
MyVar: [Integer](/page/Integer);
The implementation section then provides the private details, including the bodies of procedures and functions declared in the interface, as well as any internal-only declarations like local types or helper routines. This separation ensures that changes to implementation details do not affect dependent code, enforcing information hiding. Visibility is strictly controlled: elements in the interface are accessible externally via the unit name (e.g., MyUnit.MyVar), while implementation elements remain confined to the unit itself.[46][45]
Units may include an optional uses clause to import dependencies, listed after the unit or program declaration and separated by commas, such as uses SysUtils, Classes;. The uses clause can appear in both the interface and implementation sections; interface-level imports expose their identifiers to clients of the unit, while implementation-level imports keep dependencies private. This allows for selective namespacing, reducing namespace pollution and circular dependencies in large projects. To resolve naming conflicts, qualified names like SysUtils.DateTimeToStr can be used.[46][45]
Additionally, units support initialization and finalization sections at the end of the implementation, executed automatically when the unit is loaded or unloaded, respectively. The initialization block runs code for setup tasks, such as initializing global variables or registering components, in the order of unit dependencies at program startup. The finalization block handles cleanup, like freeing resources, and executes in reverse order upon shutdown or unit unloading; a unit requires an initialization section to include finalization. For instance:
implementation
initialization
MyVar := 0; // Setup code
finalization
// Cleanup code
implementation
initialization
MyVar := 0; // Setup code
finalization
// Cleanup code
This ensures deterministic resource management without manual intervention in the main program.[47][45]
For larger-scale modularity, particularly in Delphi implementations, packages provide runtime-loadable modules that group multiple units into deployable binaries (e.g., .bpl files on Windows). Declared in .dpk source files using the package keyword, they facilitate component libraries, plugins, and distributed development by allowing dynamic loading and shared code across applications, extending unit-based modularity to support DLLs and shared libraries. Unlike standard Pascal's static program compilation, this enables Object Pascal to build extensible systems with on-demand loading, reducing memory footprint in enterprise applications.[48][49]
Exception Handling and RTTI
Object Pascal provides robust exception handling mechanisms to manage runtime errors gracefully, allowing programs to detect, report, and recover from issues without abrupt termination. Exceptions are objects derived from the base Exception class, which encapsulates error details such as a descriptive message and help context. This approach integrates seamlessly with the language's object-oriented features, enabling structured error propagation through the call stack.[50]
The core syntax for exception handling revolves around protected blocks using try-except and try-finally constructs. In a try-except block, code within the try section executes, and if an exception occurs, control transfers to the except section for handling; an optional else clause runs if no exception is raised. The try-finally block ensures that cleanup code in the finally section always executes, regardless of exceptions, which is crucial for resource management like freeing memory or closing files. Exceptions are raised using the raise statement, typically by instantiating an exception class and passing a message, such as raise EMyException.Create('Error description'). Custom exceptions are defined by inheriting from the Exception class, as detailed in the object-oriented programming features.[50][51]
Object Pascal includes several built-in exception classes for common runtime errors, such as EInOutError for input/output failures and EDivByZero for division-by-zero operations. These are automatically raised by the runtime system in response to detectable errors, like arithmetic overflows or invalid file accesses. Developers can extend this by creating specialized subclasses, ensuring type-safe catching via on E: EClassName do clauses in except blocks. In Free Pascal implementations, exceptions must be explicitly enabled via compiler modes like ObjFPC or Delphi, as they are disabled by default to optimize performance.[50][51][52]
Runtime Type Information (RTTI) in Object Pascal enables programs to inspect and manipulate type metadata at runtime, supporting advanced features like dynamic invocation and serialization. RTTI generation is controlled by compiler directives: the legacy {$M+} enables it for classes and their published members, while the modern {$RTTI EXPLICIT METHODS(...)} or {$RTTI ALL} provides finer control, including for fields, properties, and methods. By default, RTTI is minimal to reduce executable size, but enabling it for a class or its ancestors automatically includes type data for published properties, which are accessible at design time in frameworks like the Visual Component Library (VCL).[53][54]
Access to RTTI is facilitated through units like TypInfo and the extended System.Rtti namespace, where functions such as GetTypeData(TypeInfo) retrieve detailed type descriptors, including class ancestry, field offsets, and method signatures. Dynamic class registration occurs via procedures like RegisterClass in the Classes unit, allowing runtime instantiation of registered types by name, which is essential for loading components from streams. Common applications include serialization, where RTTI drives the persistence of objects to files or streams in VCL applications, and introspection, enabling tools like the Object Inspector to display and edit published properties during development. In Free Pascal, similar RTTI capabilities support enumeration-to-string conversions and basic type queries via TypInfo.[53][55][56]
Since Delphi 2009, Object Pascal's generics have integrated with enhanced RTTI, allowing type-safe collections and operations on generic types through the System.Generics.Collections unit. This enables runtime reflection on generic instances, such as querying type constraints or invoking methods dynamically, while maintaining compile-time safety for parameterized types like TList<T>. The System.Rtti unit provides invocable types and attributes that extend to generics, facilitating frameworks for dependency injection and data binding without sacrificing performance. As of Delphi 13 (2025), additional constraints for generic types have been introduced, such as support for more specific type requirements, improving flexibility and safety in generic programming.[55][57]
Implementations
Compilers
The Free Pascal Compiler (FPC) is an open-source, multi-platform compiler that supports Object Pascal across a wide range of operating systems, including Windows, Linux, macOS, and various embedded systems.[31] It implements dialects compatible with ISO Pascal standards, as well as extensions from Turbo Pascal (TP) and Delphi, enabling the compilation of legacy and modern codebases.[58] The latest stable release, version 3.2.2 from May 2021, includes an LLVM backend for improved code generation and optimization on supported targets.[31] FPC's flexibility is enhanced by compiler modes such as {$MODE [DELPHI](/page/Delphi)} for Delphi dialect compatibility, which supports a wide range of Delphi features, including classes, interfaces, and constructs from versions up to 2009 and later, and {$MODE TP} for Turbo Pascal compatibility, allowing direct compilation of older procedural code.[58][59]
The Embarcadero Delphi Compiler (DCC), part of the proprietary RAD Studio suite, is optimized for high-performance native code generation targeting Windows, iOS, Android, macOS, and Linux.[60] It employs modern Object Pascal features, including generics, anonymous methods, and Automatic Reference Counting (ARC) for memory management in recent versions like RAD Studio 13, which enhances safety on mobile platforms without manual garbage collection.[5][57] DCC integrates advanced optimizations, such as 64-bit compilation with large memory addressing in its command-line variants (dcc32 and dcc64), and supports cross-compilation for multi-device deployment.[61]
Oxygene, formerly known as Smart Pascal and developed by RemObjects Software, is a cross-platform compiler that targets modern ecosystems including .NET, Java, JavaScript, and native platforms via LLVM.[62] It extends Object Pascal with contemporary language constructs while maintaining compatibility with Delphi syntax, allowing developers to compile the same codebase to web, desktop, and mobile environments.[63] The latest stable release, version 12.0.0.3035 from November 2025, includes support for locking expressions and mapped constructors to facilitate integration with platform-specific APIs.[64]
Legacy compilers include Turbo Pascal, which introduced object-oriented extensions in version 5.5 (1989) and reached version 7.0 in 1992, pivotal to Object Pascal's evolution, primarily for DOS and early Windows environments.[65] Borland's Kylix, released in 2000, with version 3 in 2002, and discontinued in 2005, was an early attempt at a Linux-native Object Pascal compiler based on Delphi, supporting Qt for graphical applications but limited by platform-specific challenges.[66]
Interpreters and Transpilers
Object Pascal interpreters enable dynamic execution of code subsets at runtime, facilitating scripting and interactive development without full compilation. These tools typically support a dialect of the language compatible with Delphi or Free Pascal environments, allowing integration into host applications for tasks like automation or extensibility.[67][68]
One prominent interpreter is PascalScript, a free engine developed by RemObjects Software that embeds most Object Pascal constructs within Delphi or Free Pascal projects for runtime evaluation. It compiles scripts to bytecode for efficient interpretation, supporting features like procedures, classes, and exceptions, though it omits advanced elements such as certain generics or inline assembly to maintain simplicity and performance in embedded scenarios.[67][69]
DWScript, originally created by Matthias Ackermann and Hannes Danzl in 2000, serves as another object-oriented scripting engine based on Delphi syntax with extensions from Free Pascal and Oxygene. It processes scripts through parsing and tokenization to generate executable bytecode, enabling general-purpose use beyond web contexts, such as plugin systems or dynamic behaviors in applications.[70][68]
PascalABC.NET functions as a hybrid compiler-interpreter targeting the .NET platform, developed jointly by Russian and German teams at institutions like the Institute of Mathematics and Mechanics. Its interactive mode allows immediate execution of Object Pascal code snippets, making it suitable for educational purposes with support for dynamic arrays and .NET interop, while compiling to IL for broader deployment.[71][72]
Transpilers for Object Pascal focus on converting code or headers between languages, aiding interoperability rather than direct execution. H2Pas, included in Free Pascal distributions, translates C header files into equivalent Pascal units by mapping declarations like structs to records and functions to procedures, handling common constructs but requiring manual adjustments for complex macros or unions.[73]
Oxygene, part of the Elements toolchain from RemObjects Software, extends Object Pascal to target multiple backends, including .NET via its Echoes mode, which compiles to Common Intermediate Language (CIL) for seamless integration with C# or other .NET languages. This allows developers to write Object Pascal code that transpiles to bytecode executable on the CLR, supporting mixed-language projects with features like classes and generics preserved across targets.[74][75]
These interpreters and transpilers find applications in runtime scripting for plugins and games, such as embedding scripts in Delphi-based engines for modifiable behaviors, and educational tools for interactive learning. For instance, PascalScript and DWScript enable dynamic content in legacy game frameworks like DelphiX, where scripts handle AI or events without recompiling the host.[67][68] Ports to WebAssembly, supported natively by Free Pascal, extend Object Pascal to browser environments, though Emscripten-based approaches are more common for C/C++ interop in web ports.[76]
Limitations include restricted language subsets, where full support for advanced features like complete runtime type information (RTTI) is often absent in interpreted modes to prioritize speed and embedding feasibility; for example, PascalScript omits RTTI for dynamic class inspection, relying instead on explicit type declarations.[67] Similarly, transpilers like H2Pas may not fully preserve semantic nuances, necessitating post-processing for production use.[73]
Integrated Development Environments
Object Pascal development is supported by several integrated development environments (IDEs) that provide visual tools for rapid application development, debugging, and code management. The primary commercial IDE is Embarcadero's RAD Studio 13 Florence (released September 2025), which includes Delphi as its flagship environment for Object Pascal. RAD Studio features a visual form designer for creating user interfaces, an integrated debugger for stepping through code and inspecting variables, and a profiler for performance analysis. It also supports FireMonkey (FMX), a cross-platform UI framework that enables deployment to Windows, macOS, iOS, Android, and Linux from a single codebase.[60][77][78][61]
For open-source alternatives, the Lazarus 4.4 IDE (released 2025), built around the Free Pascal compiler, serves as a Delphi-compatible environment. Lazarus offers a drag-and-drop form designer using the Lazarus Component Library (LCL) widget set, which mimics Delphi's Visual Component Library (VCL) for cross-platform compatibility across Windows, macOS, Linux, and other systems. It includes a project manager for handling multi-unit projects, an integrated debugger, and support for large-scale applications, all under the GPL/LGPL licenses.[79][80][81][82]
Modern lightweight options include extensions for Visual Studio Code, such as OmniPascal (last updated 2022), which provides Object Pascal support for both Delphi and Free Pascal dialects, including syntax highlighting, code completion (IntelliSense), declaration navigation, and error detection, integrating seamlessly with the Free Pascal compiler for building and testing on Windows, macOS, and Linux. A more recently maintained alternative is the Pascal LSP extension, which uses the Language Server Protocol with CodeTools from Lazarus for enhanced features like diagnostics and refactoring.[83][84]
Borland's C++Builder IDE, introduced in 1997 and now integrated into Embarcadero's RAD Studio, shares the same environment as Delphi, allowing mixed Object Pascal and C++ development with the VCL for Windows applications, as well as cross-platform support via FMX. Earlier, the Turbo Pascal IDE from the 1980s was a DOS-based tool that pioneered integrated editing, compilation, and debugging in a compact, fast interface, influencing modern IDE designs.[85][86][61]
Common productivity features across these IDEs include code completion for suggesting identifiers and parameters, refactoring tools for renaming symbols or extracting methods without breaking dependencies, and integration with unit testing frameworks like DUnitX. DUnitX, an open-source testing library, allows developers to write and run tests directly within the IDE, supporting assertions, setup/teardown methods, and parameterized tests to ensure code reliability. These features, particularly prominent in RAD Studio, enhance developer efficiency by automating routine tasks and providing real-time feedback during coding.[87][88]
Build Systems and Utilities
Free Pascal provides fpcmake, a makefile generator that reads a Makefile.fpc configuration file and produces a standard Makefile compatible with GNU make for compiling projects.[89] This tool supports conditional compilation through directives in the Makefile.fpc, allowing developers to define build targets, dependencies, and platform-specific options, such as cleaning binaries or installing packages.[90] For instance, sections like [clean], [compiler], and [install] in the configuration file enable automated handling of compilation tasks across multiple units and executables.[90]
In contrast, Delphi integrates with Microsoft's MSBuild system, utilizing .dproj project files to orchestrate builds from the command line.[91] These XML-based files encapsulate project settings, including compiler options and dependencies, facilitating automated builds in continuous integration/continuous deployment (CI/CD) pipelines without relying on the IDE.[91] Developers invoke MSBuild.exe directly on a .dproj file, specifying configurations like Debug or Release, to compile applications, packages, or project groups efficiently.[91]
Several utilities enhance project management in Object Pascal ecosystems. FPDoc scans Pascal unit source files to generate documentation in formats such as HTML or LaTeX, extracting comments and identifiers from the interface section to produce structured help files.[92] Command-line options allow customization of output, including cross-references between units. Lazbuild serves as a command-line counterpart for Lazarus projects, recursively resolving dependencies, compiling required packages, and building executables or the IDE itself from .lpi or .lpk files.[93]
Package management tools streamline component acquisition. Embarcadero's GetIt Package Manager, integrated into RAD Studio, enables browsing, downloading, and installing third-party components, libraries, and samples directly within the IDE or via command-line scripts.[94] For Free Pascal, the fppkg tool handles installation and updates of packages defined with FPMake, supporting offline repositories for embedded or constrained environments.[95]
Cross-compilation setups in Free Pascal target platforms like ARM on Raspberry Pi through dedicated toolchains. Developers configure the compiler with cross-binutils and target-specific libraries, such as arm-linux, to build binaries from a host like x86 Linux, ensuring compatibility with Raspberry Pi's ARM architecture by installing Pi-specific RTL and FCL units.[96] This process involves bootstrapping the cross-compiler and verifying with flags like -Tlinux -Parm, enabling deployment to embedded devices without native compilation.[97]
Code Examples
Basic Programs
Object Pascal programs follow a procedural structure, beginning with a program declaration followed by variable declarations and a main begin-end block for executable statements. This foundational syntax, inherited from earlier Pascal dialects, emphasizes readability and type safety, making it suitable for introductory programming. Basic programs typically avoid object-oriented features, focusing instead on control structures, variables, and input/output operations across implementations like Turbo Pascal, Delphi, and Free Pascal.
A canonical "Hello World" program in Turbo Pascal demonstrates the simplest form of output using the WriteLn procedure. The code is structured as follows:
program Hello;
begin
WriteLn('Hello World');
end.
program Hello;
begin
WriteLn('Hello World');
end.
This program declares a main block that prints the string to the console and implicitly handles program termination. Turbo Pascal, developed by Borland in the 1980s, uses this concise syntax for console applications, where WriteLn appends a newline.
Stack allocation for strings in Object Pascal occurs automatically within the variable declaration section, promoting efficient memory use without explicit management. Consider this example, compatible with Turbo Pascal and extended dialects:
var
s: String;
begin
s := 'Hello';
WriteLn(s);
end.
var
s: String;
begin
s := 'Hello';
WriteLn(s);
end.
Here, s is allocated on the stack as a fixed-length string (up to 255 characters in Turbo Pascal), assigned a value, and output via WriteLn. This approach contrasts with dynamic allocation and underscores Pascal's strong typing, where string literals are directly assignable.
For heap allocation, Free Pascal provides procedures like GetMem and FreeMem to manage dynamic memory, essential for variable-sized data. An example using a pointer to a character array illustrates this:
var
p: PChar;
begin
GetMem(p, 6);
StrPCopy(p, 'Hello');
WriteLn(p);
FreeMem(p);
end.
var
p: PChar;
begin
GetMem(p, 6);
StrPCopy(p, 'Hello');
WriteLn(p);
FreeMem(p);
end.
This allocates 6 bytes (for 'Hello' plus null terminator) on the heap, copies the string using StrPCopy, prints it, and deallocates to prevent memory leaks. Free Pascal extends Turbo Pascal's model with enhanced pointer safety and compatibility modes.
Control structures such as loops and conditionals form the core of procedural logic in Object Pascal. A simple for loop combined with an if statement can iterate and filter values, as shown:
var
i: Integer;
begin
for i := 1 to 5 do
if i mod 2 = 0 then
WriteLn('Even');
end.
var
i: Integer;
begin
for i := 1 to 5 do
if i mod 2 = 0 then
WriteLn('Even');
end.
This outputs "Even" for i=2 and i=4, using the modulo operator (mod) for remainder calculation. The for loop handles integer ranges inclusively, and the if-then branch executes conditionally without needing braces, aligning with Pascal's indentation-free style.
Dialect variations affect string handling: Turbo Pascal employs ShortString (fixed-length, first byte as length indicator), while modern Delphi (since 2009) uses UnicodeString as the default for dynamic, reference-counted Unicode strings, with AnsiString available for legacy 8-bit character handling, improving performance in modern applications but requiring careful management of lifetimes.[98]
Object-Oriented Demonstrations
Object Pascal supports object-oriented programming through classes, inheritance, interfaces, properties, and exception handling integrated into object contexts. These features enable encapsulation, polymorphism, and modular design in applications developed with compilers like Delphi and Free Pascal. The following demonstrations illustrate key OOP elements using representative code snippets, assuming a unit-based structure where these declarations appear in the interface and implementation sections.
A simple class declaration defines fields, constructors, and methods within a class type. For instance, the TPerson class encapsulates a name and provides a constructor and getter method:
pascal
type
TPerson = [class](/page/Class)(TObject)
private
FName: [string](/page/String);
public
constructor Create(const AName: [string](/page/String));
[function](/page/Function) GetName: [string](/page/String);
end;
constructor TPerson.Create(const AName: [string](/page/String));
begin
FName := AName;
end;
function TPerson.GetName: [string](/page/String);
begin
Result := FName;
end;
type
TPerson = [class](/page/Class)(TObject)
private
FName: [string](/page/String);
public
constructor Create(const AName: [string](/page/String));
[function](/page/Function) GetName: [string](/page/String);
end;
constructor TPerson.Create(const AName: [string](/page/String));
begin
FName := AName;
end;
function TPerson.GetName: [string](/page/String);
begin
Result := FName;
end;
This example creates an instance via var P: TPerson; P := TPerson.Create('John'); Writeln(P.GetName);, demonstrating basic instantiation and method invocation.[99]
Inheritance allows a derived class to extend a base class, inheriting its members and optionally overriding methods for polymorphism. Consider TEmployee inheriting from TPerson and overriding a virtual Describe method:
pascal
type
TPerson = [class](/page/Class)(TObject)
public
function Describe: string; [virtual](/page/Virtual);
end;
TEmployee = class(TPerson)
private
FSalary: Real;
public
constructor Create(const AName: string; ASalary: Real);
function Describe: string; override;
end;
function TPerson.Describe: string;
begin
Result := 'A person';
end;
constructor TEmployee.Create(const AName: string; ASalary: Real);
begin
inherited Create(AName);
FSalary := ASalary;
end;
function TEmployee.Describe: string;
begin
Result := inherited Describe + ' earning ' + FloatToStr(FSalary);
end;
type
TPerson = [class](/page/Class)(TObject)
public
function Describe: string; [virtual](/page/Virtual);
end;
TEmployee = class(TPerson)
private
FSalary: Real;
public
constructor Create(const AName: string; ASalary: Real);
function Describe: string; override;
end;
function TPerson.Describe: string;
begin
Result := 'A person';
end;
constructor TEmployee.Create(const AName: string; ASalary: Real);
begin
inherited Create(AName);
FSalary := ASalary;
end;
function TEmployee.Describe: string;
begin
Result := inherited Describe + ' earning ' + FloatToStr(FSalary);
end;
Here, inherited calls the base implementation, allowing TEmployee to build upon TPerson's behavior.[100]
Interfaces define contracts for classes without implementing them, promoting loose coupling. An example is the IShape interface with an Area method, implemented by the TCircle class:
pascal
type
IShape = [interface](/page/Interface)
['{12345678-1234-1234-1234-123456789ABC}']
function Area: Real;
end;
TCircle = [class](/page/Class)(TInterfacedObject, IShape)
private
FRadius: Real;
public
constructor Create(ARadius: Real);
function Area: Real;
end;
constructor TCircle.Create(ARadius: Real);
begin
FRadius := ARadius;
end;
function TCircle.Area: Real;
begin
Result := Pi * FRadius * FRadius;
end;
type
IShape = [interface](/page/Interface)
['{12345678-1234-1234-1234-123456789ABC}']
function Area: Real;
end;
TCircle = [class](/page/Class)(TInterfacedObject, IShape)
private
FRadius: Real;
public
constructor Create(ARadius: Real);
function Area: Real;
end;
constructor TCircle.Create(ARadius: Real);
begin
FRadius := ARadius;
end;
function TCircle.Area: Real;
begin
Result := Pi * FRadius * FRadius;
end;
Usage involves querying the interface: var S: IShape; C := TCircle.Create(5); S := C as IShape; Writeln(S.Area);. This supports COM-style interoperability and reference counting via IInterface.[101]
Properties provide controlled access to private fields, using read and write specifiers. In the TPerson class, an Age property with a setter validates input:
pascal
type
TPerson = class(TObject)
private
FAge: Integer;
procedure SetAge(AValue: Integer);
public
property Age: Integer read FAge write SetAge;
end;
procedure TPerson.SetAge(AValue: Integer);
begin
if (AValue >= 0) and (AValue <= 150) then
FAge := AValue
else
raise ERangeError.Create('Invalid age');
end;
type
TPerson = class(TObject)
private
FAge: Integer;
procedure SetAge(AValue: Integer);
public
property Age: Integer read FAge write SetAge;
end;
procedure TPerson.SetAge(AValue: Integer);
begin
if (AValue >= 0) and (AValue <= 150) then
FAge := AValue
else
raise ERangeError.Create('Invalid age');
end;
Access occurs as P.Age := 30; Writeln(P.Age);, abstracting field manipulation.[102]
Exceptions in OOP contexts handle errors during object operations, such as invalid method calls. Within a class method, a try-except block catches specific exceptions:
pascal
type
TCalculator = [class](/page/Class)(TObject)
public
[function](/page/Function) Divide(A, B: Real): Real;
end;
function TCalculator.[Divide](/page/Function)(A, B: Real): Real;
begin
if B = 0 then
raise EZeroDivide.Create('[Division by zero](/page/Division_by_zero)');
Result := A / B;
end;
// Usage
var
Calc: TCalculator;
Res: Real;
begin
Calc := TCalculator.Create;
try
Res := Calc.[Divide](/page/Function)(10, 0);
except
on E: EZeroDivide do
Writeln('Error: ' + E.Message);
end;
Calc.Free;
end.
type
TCalculator = [class](/page/Class)(TObject)
public
[function](/page/Function) Divide(A, B: Real): Real;
end;
function TCalculator.[Divide](/page/Function)(A, B: Real): Real;
begin
if B = 0 then
raise EZeroDivide.Create('[Division by zero](/page/Division_by_zero)');
Result := A / B;
end;
// Usage
var
Calc: TCalculator;
Res: Real;
begin
Calc := TCalculator.Create;
try
Res := Calc.[Divide](/page/Function)(10, 0);
except
on E: EZeroDivide do
Writeln('Error: ' + E.Message);
end;
Calc.Free;
end.
This ensures robust error recovery without terminating the program.[103]
Dialect variations appear in Delphi, where published properties enable runtime type information (RTTI) for visual components like VCL controls. Declared in the published section, they support design-time editing and serialization:
pascal
type
TMyControl = class(TControl)
private
FColor: TColor;
procedure SetColor(AValue: TColor);
published
property Color: TColor read FColor write SetColor default clRed;
end;
type
TMyControl = class(TControl)
private
FColor: TColor;
procedure SetColor(AValue: TColor);
published
property Color: TColor read FColor write SetColor default clRed;
end;
The {$M+} directive or descent from TPersistent generates RTTI for these, distinguishing Delphi from other Object Pascal implementations like Free Pascal, which may require explicit attributes.[99]