nenu-lang / presence-guards
Stable

Presence Guards

  • with runs when an optional is present; without runs when it is absent.
  • Use as name for a readable non-optional binding, or use the implicit it binding.
  • An else branch handles the opposite state and may bind the present value after without.

With: Run When Present

code
1with expense.note as note {2  label = note.trim()3}

Inside the block, the binding has the unwrapped non-optional type. A named binding is clearer when the block has more than one statement or when nested scopes also use it.

Without: Run When Absent

code
1without expense.note {2  expense.note = "No receipt note"3}

without is useful for initialization, required-value diagnostics, and fallback actions that take more than one expression.

Handling Both Paths

code
1with expense.receipt as receipt {2  label = receipt.name3} else {4  label = "No receipt"5}

After without, the else path is the present path and may bind the value with as name. Keep the branch that reads most naturally for the decision you are expressing.

Guarding Indexed Values

code
1with expenses[0] as first_expense {2  selected = first_expense3}45with balances[member_id] as amount {6  current_balance = amount7}

Normal array and map indexes are optional, so the same guard syntax proves a position or key exists before using the value.

Narrowing Scope And Reassignment

  • The narrowed binding exists only inside its branch.
  • The original expression remains optional outside the guard.
  • Prefer a named binding if the original path may be assigned inside the block.
  • Do not assume a previous guard proves presence after unrelated mutation or outside its scope.

Choose A Guard Or Coalesce

NeedUse
One expression with a fallbackvalue ?? fallback
Several statements when presentwith value as present { ... }
Several statements when absentwithout value { ... }
Different work for both pathsAdd else.
Read an optional as required without proofDo not; guard or coalesce first.

Common Mistakes

MistakeCorrection
Read a field from an optional directlyNarrow it with with first.
Use without as a presence branchUse with for the present value.
Use a guard binding after its blockKeep narrowed access inside the guard scope.
Use a multi-statement guard for one fallback expressionPrefer ?? for the simple case.

Continue Learning