TGL: Operators
TGL: Operators
TGL has comparison, logical, and nullish-coalescing operators. It deliberately doesn’t have arithmetic operators. This page also covers TGL’s strict-typing semantics, which interact with operators in ways worth knowing about.
Comparison
$out.is_admin = $row.role == "admin"
$out.is_recent = $row.age < 30
$out.has_orders = $row.order_count >= 1
$out.eligible = $row.status != "banned" Available: ==, !=, <, >, <=, >=. == does strict equality (no type coercion, so "5" == 5 is false).
Logical
$out.flagged = $row.suspicious && $row.score < 0.5
$out.notify = $row.subscribed || $row.opted_in
$out.is_invalid = !$row.is_valid && and || short-circuit. ! negates.
Truthiness is standard: null, undefined, 0, "", false, and NaN are falsy; everything else is truthy.
Nullish coalescing: ??
$out.label = $row.label ?? "untitled"
$out.country = $row.address.country ?? $row.user.country ?? "US" a ?? b returns a unless a is null or undefined, in which case it returns b. Critically, ?? does NOT treat 0, "", or false as missing. Only null/undefined triggers the fallback. Use this when you want a default for “really missing,” not for “falsy.”
$out.count = $row.count ?? 0 // 0 if count is null
$out.checked = $row.opted_in ?? false // false if opted_in is null What’s not here: arithmetic
There are no +, -, *, /, % operators. Use the math functions instead:
$out.total = multiply($row.price, $row.qty)
$out.with_tax = add($out.total, multiply($out.total, $row.tax_rate))
$out.average = divide($out.total, $row.count) The reason: arithmetic operators in JS-like languages have surprising coercions ("5" + 3 is "53", null + 1 is 1, [] + {} is "[object Object]"). TGL’s function-call form makes the type intent explicit. add accepts numbers and treats null as 0; other types return null. There is no silent string-numeric mixing.
Type semantics
Strict typing
Functions don’t coerce silently. If add gets a string, you get null:
$out.total = add($row.x, $row.y)
// row.x = 5, row.y = 3 returns 8
// row.x = "5", row.y = 3 returns null (string isn't a number)
// row.x = null, row.y = 3 returns 3 (null treated as 0 in add)
// row.x = 5, row.y = "abc" returns null (still null, abc isn't a number) This is intentional. Silent type coercion can create subtle data bugs. TGL surfaces a math type mismatch as null. If your math involves a numeric string, add an int(...) or float(...) conversion.
Null propagation
Most functions return null when given null (or any wrong type). This propagates: lowerCase(trim($row.email)) returns null cleanly when email is missing, instead of throwing.
The exceptions are documented per-function. Most notably add and subtract, which treat null as 0 to make accumulators ergonomic.