Types

PXX implements a traditional Object Pascal type system: ordinals, real numbers, strings, enumerations, records, and arrays. Every example on this page compiles and runs on the pinned compiler.

Ordinal types

Integers and the types built on them (Byte, Char, Boolean, enumerations). Integer is 32-bit; Int64 is 64-bit.

Type Size Range
Byte 1 0 … 255
ShortInt 1 -128 … 127
Word 2 0 … 65535
SmallInt 2 -32768 … 32767
LongWord 4 0 … 4294967295
Integer 4 -2147483648 … 2147483647
Int64 8 signed 64-bit
Boolean 1 False / True
Char 1 a single byte

Ordinal helpers: Ord, Succ, Pred, Inc, Dec, Low, High, Odd.

Real types

Single (4-byte), Double (8-byte), and Real (alias of Double). Write with a field-width/precision suffix:

writeln(f:0:1);   { 3.5 }

Strings

string is a managed, reference-counted, length-prefixed type — it grows automatically and frees itself. Length, Copy, Pos, IntToStr, and + concatenation all work on it. This is the default.

There is also an older frozen string ABI: a fixed-capacity inline buffer instead of a heap allocation, with no reference counting. Select it by undefining the managed-string symbol at compile time:

./pxx -uPXX_MANAGED_STRING hello.pas hello

The frozen ABI trades away automatic growth and copy-on-write for a smaller, simpler runtime footprint — useful for size-constrained targets or when you want to avoid heap traffic entirely. Prefer the default managed strings unless you have a specific reason to opt out.

Enumerations

type
  TColor = (cRed, cGreen, cBlue);

Ord(cGreen) is 1. Enumerations are ordinals — usable in case, for, and array indexing.

Records

type
  TPoint = record
    X, Y: Integer;
  end;

Access fields with .. Records are value types — assignment copies the whole record. Variant records (a case part sharing storage) are supported.

Advanced records

Records can also carry methods, visibility sections, constructors, and operator overloads — they stay value types, but gain much of a class's surface without heap allocation. Operators use the symbol form (class operator + (...)), not Delphi's named form (class operator Add):

program advanced_record_demo;

type
  TVec = record
    X, Y: Integer;
    constructor Create(ax, ay: Integer);
    function Len2: Integer;
    class operator + (const a, b: TVec): TVec;
  end;

constructor TVec.Create(ax, ay: Integer);
begin
  X := ax;
  Y := ay;
end;

function TVec.Len2: Integer;
begin
  Result := X * X + Y * Y;
end;

class operator TVec.+ (const a, b: TVec): TVec;
begin
  Result.X := a.X + b.X;
  Result.Y := a.Y + b.Y;
end;

var
  a, b, c: TVec;
begin
  a := TVec.Create(1, 2);
  b := TVec.Create(3, 4);
  c := a + b;
  writeln(c.X, ',', c.Y, ' len2=', c.Len2);   { 4,6 len2=52 }
end.

Arrays

Fixed arrays have a compile-time index range:

var fixed: array[1..3] of Integer;

Dynamic arrays start empty and are sized with SetLength; they are 0-indexed and managed:

var dyn: array of Integer;
...
SetLength(dyn, 2);
dyn[0] := 1;
writeln(Length(dyn));   { 2 }

Pointers and Typed Pointers

PXX supports low-level pointer operations, including typed pointers, address-of operations, and pointer arithmetic:

[!IMPORTANT] When writing portable code for both 32-bit and 64-bit targets, use ^NativeInt instead of ^Int64 for pointer-sized integer storage. A write to ^Int64 is always 8 bytes and will overrun a 4-byte slot on 32-bit platforms.

var
  x: Integer;
  p: ^Integer;
begin
  x := 42;
  p := @x;      { p points to x }
  p^ := 100;    { dereference and assign }
  writeln(x);   { prints 100 }
end;

Sets

Sets in PXX represent a collection of values of the same ordinal type (such as bytes, characters, or enumerations). A set is backed internally by a 32-byte bitset, supporting up to 256 elements.

Set Operations

type
  TCharSet = set of Char;
var
  letters: TCharSet;
begin
  letters := ['a', 'b', 'c'];
  if 'b' in letters then
    writeln('b is present');
    
  letters := letters + ['d'] - ['a']; { ['b', 'c', 'd'] }
end;

Variants

PXX supports a built-in Variant type. A Variant can hold values of different types dynamically (such as integers, characters, real numbers, booleans, and strings) and can change its type at runtime through reassignment.

Key Characteristics

[!NOTE] In this dialect, boolean values stored in a Variant print as 0 for False and 1 for True when using writeln.

var
  v, w: Variant;
begin
  v := 42;      { v holds Integer }
  writeln(v);   { prints 42 }
  
  v := 'Q';     { v now holds Char }
  writeln(v);   { prints Q }
  
  v := 3.14;    { v now holds Double }
  writeln(v);   { prints 3.14 }
  
  v := 'hello ';
  w := 'world';
  writeln(v + w); { prints "hello world" }
end;

Putting it together

program types_demo;
type
  TColor = (cRed, cGreen, cBlue);
  TPoint = record
    X, Y: Integer;
  end;
  TCharSet = set of Char;
var
  i: Integer;
  b: Byte;
  f: Double;
  c: TColor;
  s: string;
  fixed: array[1..3] of Integer;
  dyn: array of Integer;
  p: TPoint;
  ptr: ^Integer;
  letters: TCharSet;
  v: Variant;
begin
  i := -42;
  b := 255;
  f := 3.5;
  c := cGreen;
  s := 'pxx';
  fixed[1] := 10; fixed[2] := 20; fixed[3] := 30;
  SetLength(dyn, 2);
  dyn[0] := 1; dyn[1] := 2;
  p.X := 7; p.Y := 9;
  
  // Pointer demo
  ptr := @i;
  ptr^ := 100;
  
  // Set demo
  letters := ['a', 'b', 'c'];
  letters := letters + ['d'] - ['a'];
  
  // Variant demo
  v := 'variant string';
  
  writeln(i, ' ', b, ' ', f:0:1, ' ', Ord(c));
  writeln(s, ' len=', Length(s));
  writeln(fixed[2], ' ', dyn[1], ' ', Length(dyn));
  writeln(p.X, ',', p.Y);
  writeln('ptr^: ', ptr^);
  if 'b' in letters then writeln('b in set');
  if not ('a' in letters) then writeln('a not in set');
  writeln('v: ', v);
end.

Output:

100 255 3.5 1
pxx len=3
20 2 2
7,9
ptr^: 100
b in set
a not in set
v: variant string

Next