Classes & Objects

DWScript is fully object-oriented, supporting classes, inheritance, polymorphism, and encapsulation.

Usage Examples

type
  TAnimal = class
    FName : String;
    constructor Create(const name : String);
    begin
       FName := name;
    end;
    procedure Speak; virtual;
    begin
       PrintLn(FName + ' makes a sound');
    end;
  end;

type
  TDog = class(TAnimal)
    procedure Speak; override;
    begin
       PrintLn(FName + ' barks');
    end;
  end;

var myPet := new TDog('Buddy');
myPet.Speak;
Result
Buddy barks

Classes

A class is a blueprint for objects. In DWScript, classes support several modifiers to control inheritance and instantiation.

Declaration Syntax

While you can use the standard procedure and function keywords, DWScript also supports the method keyword as a unified alternative for declaring any member subroutine within a class. It is fully interchangeable with procedure (if no return type) or function (if return type is specified).

type
  TMyClass = class
    method DoSomething; begin end;
    method Calculate: Integer; begin Result := 0; end;
    class method StaticAction; begin end;
  end;
Modifier Description
abstract The class cannot be instantiated directly. It must be inherited.
sealed The class cannot be inherited from.
static A class that only contains static (class) members. It cannot be instantiated.
partial Allows splitting a class definition across multiple files or sections.

Static Classes

A static class is used to group related global functions and variables. It cannot be instantiated using new or Create.

type
  TUtils = static class
    class procedure SayHello;
    begin
       PrintLn('Hello from Static Class');
    end;
  end;

TUtils.SayHello;
// var u := new TUtils; // Error: Cannot instantiate static class
Result
Hello from Static Class

Partial Classes

The partial modifier allows a class to be defined in multiple parts. This is useful for large classes or when combining generated code with manual code.

type
  TBigClass = partial class
    procedure MethodA; begin PrintLn('A'); end;
  end;

type
  TBigClass = partial class
    procedure MethodB; begin PrintLn('B'); end;
  end;

var obj := new TBigClass;
obj.MethodA;
obj.MethodB;
Result
A
B

Inner Classes (Nested Types)

DWScript supports defining classes within other classes. These are known as inner or nested classes. They are useful for grouping helper classes that are only relevant to the outer class.

type
  TOuter = class
    type
      TInner = class
        function GetMsg: String;
        begin
           Result := 'Hello from Inner';
        end;
      end;
    procedure Run;
    begin
       var i := new TInner;
       PrintLn(i.GetMsg);
    end;
  end;

var o := new TOuter;
o.Run;
Result
Hello from Inner

Constructors & Destructors

Constructors initialize new object instances. Unlike many languages that use a fixed name like constructor or __init__, DWScript supports named constructors, following classic Pascal conventions.

Instantiation Syntax

You can instantiate an object in two ways:

  • Classic Pascal: TMyClass.Create(args). This is the traditional way to call a specific named constructor.
  • Modern Syntax: new TMyClass(args). This uses the constructor marked with the default keyword.

The "default" Keyword

A class can designate one constructor as the default. This allows the new keyword to be used without specifying the constructor name.

type
  TUser = class
    constructor Create(name: String); default;
    begin
       inherited Create; // Call parent constructor
       // ...
    end;
  end;
var u := new TUser('Alice'); // Calls TUser.Create

Overloaded Constructors

You can have multiple constructors with the same name but different parameters by using the overload modifier.

type
  TPoint = class
    constructor Create; overload; begin end;
    constructor Create(x, y: Integer); overload; begin end;
  end;

Virtual Constructors & Metaclasses

Constructors can be virtual. When combined with Metaclasses (class references), this allows for powerful dynamic instantiation patterns, such as factories, where the specific class to be created is determined at runtime.

type
  TBase = class(TObject)
    constructor Create; virtual; begin end;
  end;
type
  TDerived = class(TBase)
    constructor Create; override; begin end;
  end;
type
  TBaseClass = class of TBase;

var cls: TBaseClass := TDerived; 
var obj := cls.Create;

This "factory" pattern is a core part of DWScript's metaprogramming capabilities, allowing the system to work with types as first-class values.

Destructors

Destructors are named Destroy and are used to clean up resources.

Because DWScript uses ARC (Automatic Reference Counting), they are called automatically when the reference count reaches zero. For more details, see Memory Management.

It is best practice to always mark your destructor with override and call inherited as the last statement to ensure the base class cleanup also runs.

Class Operators

Classes can define custom behavior for standard operators using the class operator syntax. This allows objects to interact naturally with language operators like +, -, in, and implicit casts.

The syntax maps an operator to a specific method (either a static class method or a standard method).

Customizing Arithmetic/Assignment

You can define operators like += to handle custom addition logic.

type
  TLogger = class
    Buffer: String;
    procedure Append(s: String);
    begin
       Buffer := Buffer + s + #13#10;
    end;
    // Map += operator to Append method
    class operator += String uses Append;
  end;

var log := new TLogger;
log += 'Line 1';
log += 'Line 2';

PrintLn(log.Buffer);
Result
Line 1
Line 2

Customizing 'in' Operator

The in operator is particularly powerful. You can define how your class responds when checking if a value "is in" the object.

type
  TRange = class
    Min, Max: Integer;
    constructor Create(aMin, aMax: Integer);
    begin
       Min := aMin; Max := aMax;
    end;
    function Contains(i: Integer): Boolean;
    begin
       Result := (i >= Min) and (i <= Max);
    end;
    // Map 'in' operator to Contains method
    class operator in Integer uses Contains;
  end;

var r := new TRange(10, 20);

if 15 in r then
  PrintLn('15 is in range');

if 5 not in r then
  PrintLn('5 is outside range');
Result
15 is in range
5 is outside range

Advanced Features

Object Pascal in DWScript includes several advanced features for building robust applications:

On this page