The ?? operator provides a concise way to handle default values. It returns the left-hand operand if it is not the default value for its type; otherwise, it returns the right-hand operand.
The syntax is value ?? default.
var name: String := '';
PrintLn(name ?? 'Anonymous');
name := 'Alice';
PrintLn(name ?? 'Anonymous'); Anonymous Alice
The operator checks against the language-defined "empty" or "zero" state for each type.
| Type | "Empty" Condition |
|---|---|
| String | '' (Empty string) |
| Integer / Float | 0 / 0.0 |
| Object / Interface | nil |
| Boolean | False |
| Dynamic Array | nil or length 0 |
| Variant | Unassigned or Null |
Note that 0 is considered the default value for numbers.
var count := 0;
PrintLn(count ?? 10);
var price := 0.0;
PrintLn(price ?? 19.99); 10 19.99
Highly useful for ensuring an object or array is initialized.
var list: array of Integer;
// If list is empty/nil, returns a new array
var activeList := list ?? [1, 2, 3];
PrintLn(activeList.Length);
var obj: TObject := nil;
var instance := obj ?? new TObject;
PrintLn(instance.ClassName); 3 TObject
You can chain multiple ?? operators to find the first non-default value.
var input1 := '';
var input2 := '';
var input3 := 'Hello';
var result := input1 ?? input2 ?? input3 ?? 'Default';
PrintLn(result); Hello
The right-hand side of a ?? expression is only evaluated if the left-hand side is the default value.
function GetExpensiveDefault: String;
begin
PrintLn('Computing...');
Result := 'Heavy Value';
end;
var s := 'Quick Value';
// GetExpensiveDefault is NEVER called here
PrintLn(s ?? GetExpensiveDefault()); Quick Value
The coalesce operator is particularly powerful when navigating JSON structures or dynamic data where fields might be missing or null.
var data := JSON.Parse('{"id": 123}');
var title := data.title ?? 'Untitled'; // 'title' field is missing
PrintLn(title); Untitled