Skip to main content

Guard and Coalesce

Create conditional values with when guards and safely unwrap them with the ?? coalesce operator.

Use Case

You want to compute values that only exist under certain conditions, with fallback defaults.

The Pipeline

# guard-and-coalesce.cst

@example(75)
in score: Int

@example(50)
in threshold: Int

@example(true)
in enabled: Boolean

@example("Default fallback message")
in defaultMessage: String

# Guard: "expr when condition" produces Optional<T>
# If condition is true → Some(expr); if false → None
highScoreMessage = "Excellent!" when score > threshold
processingResult = "Enabled" when enabled
complexGuard = "Both conditions met" when score > 50 and enabled

# Coalesce: "optional ?? fallback" unwraps with a default
finalMessage = highScoreMessage ?? "Below threshold"

# Chained coalesce: first non-None value wins
result = highScoreMessage ?? processingResult ?? defaultMessage

# Practical: conditional bonuses with arithmetic
baseBonus = 10
highScoreBonus = 25 when score > 80
enabledBonus = 15 when enabled

actualHighBonus = highScoreBonus ?? 0
actualEnabledBonus = enabledBonus ?? 0
totalBonus = baseBonus + actualHighBonus + actualEnabledBonus

out highScoreMessage
out processingResult
out complexGuard
out finalMessage
out result
out actualHighBonus
out actualEnabledBonus
out totalBonus

Explanation

OperatorSyntaxResultPurpose
Guardexpr when conditionOptional<T>Some(expr) if true, None if false
Coalesceoptional ?? fallbackTUnwrap with fallback
Chaina ?? b ?? cTTry each in order, use first non-None

Guards produce Optional<T> values. Coalesce unwraps them. Together they replace explicit if/else patterns for conditional values with defaults.

warning

Guards produce Optional<T>, not T. You must coalesce (??) before using the value in arithmetic or passing it to a module that expects a non-optional type.

Running the Example

Input

{
"score": 75,
"threshold": 50,
"enabled": true,
"defaultMessage": "Default fallback message"
}

Expected Output

{
"highScoreMessage": "Excellent!",
"processingResult": "Enabled",
"complexGuard": "Both conditions met",
"finalMessage": "Excellent!",
"result": "Excellent!",
"actualHighBonus": 0,
"actualEnabledBonus": 15,
"totalBonus": 25
}

Variations

Tiered bonuses

in score: Int

tier1 = 50 when score >= 90
tier2 = 30 when score >= 70
tier3 = 10 when score >= 50

bonus = tier1 ?? tier2 ?? tier3 ?? 0

out bonus
tip

Chained coalesce (a ?? b ?? c ?? default) reads like a priority list. The first non-None value wins. Use this pattern for tiered defaults.

Best Practices

  1. Guard for conditional existence — use when when a value should only exist under certain conditions
  2. Always coalesce before arithmetic — unwrap Optional<T> with ?? before using the value in operations
  3. Chain for priority fallbacksa ?? b ?? c naturally expresses "try A, then B, then C"