Open Source / radNullableTypes
Focused, dependency-light nullable and tri-state value types for Delphi. A freshly declared value starts null — guaranteed, not stack garbage — lifts from a bare value implicitly, and only unwraps explicitly, so a null can never slip into ordinary code unnoticed.
radNullableTypes gives Delphi the optional-value semantics that
higher-level languages take for granted — without dragging heavyweight
RTL units into every unit that merely declares an optional field. The core
unit radNullable depends only on System.SysUtils,
System.TypInfo, and System.Generics.Defaults;
Variant / TValue / JSON conversions live in a separate
radNullable.Rtti companion so they are opt-in.
A two-state value — the Delphi equivalent of .NET
Nullable<T>. Implicit in, explicit out: a bare value
lifts automatically, but unwrapping back to T is explicit and
raises if it is null. Lenient accessors
(ValueOrDefault, TryGetValue) never raise.
A three-state value that distinguishes “field omitted” from “field explicitly null” — exactly what JSON Merge Patch and cloud update-to-clear (PATCH) semantics require.
A custom Initialize operator guarantees a freshly declared
local reads as null (or Unset) rather than stack garbage — the hard
floor of Delphi 10.4 Sydney exists precisely to make this guarantee.
Equality and ordering follow .NET Nullable<T>, not SQL
three-valued logic: null = null is true and null sorts below
every value. A ready-made cached comparer makes a nullable safe as a
dictionary or sort key, even for managed T like
string.
A freshly declared nullable starts null
uses radNullable;
var
Age: TNullable<Integer>;
begin
Assert(Age.IsNull); // guaranteed, not stack garbage
Age := 42; // implicit lift from a value
if Age.HasValue then
Writeln(Age.Value); // 42
Age := NullValue; // back to null via the sentinel
Writeln(Age.ValueOrDefault(-1)); // -1 (lenient, never raises)
Age := 7;
Writeln(Integer(Age)); // 7 -- explicit unwrap
end;
Add the source directory to your project search path
and use the units. That is the whole install — there is nothing to build
and nothing to link.
uses
radNullable, // TNullable<T>, TTriState<T>, comparer, NullValue
radNullable.Rtti; // Variant / TValue / JSON conversions (optional)