Demonstrate the difference between <? coalescing and :=? guarded assignment.

← Operators and Expressions · Ref: Q1226

<? and :=? are DIFFERENT operations despite the similar ? suffix.

<? is a COMPARISON — it returns the lesser of two values:

  cheaperOf() as pure
    -> left as Money, right as Money
    <- rtn as Money: left <? right
  //Returns the smaller Money value, handles unset

:=? is an ASSIGNMENT — it sets a variable only if unset:

  price <- Money()
  price :=? 9.99#USD
  //Assigns 9.99 USD because price was unset

KEY DIFFERENCES:

- <? compares two values and produces a result. It goes inside pure functions.
- :=? modifies a variable in place. It is an assignment, not a comparison.
- <? has a companion >? (coalescing maximum). :=? has no companion.
- <? always evaluates both sides. :=? skips the right side if the target is already set.

See Q1092 for <? and >? coalescing. See Q1038 for :=? fallback chains. See Q1227 for all four coalescing operators.

Example

defines module qa.operators.coalescevsguard

  defines function

    // <? is a COMPARISON — used inside pure functions
    cheaperOf() as pure
      ->
        left as Money
        right as Money
      <- rtn as Money: left <? right

    earlierOf() as pure
      ->
        left as Date
        right as Date
      <- rtn as Date: left <? right

  defines program

    CoalesceVsGuardDemo()
      stdout <- Stdout()

      // ============================================================
      // PART 1: <? COALESCING MINIMUM — compares two values
      // ============================================================

      // <? returns the LESSER of two values
      vendorA <- 149.99#USD
      vendorB <- 129.50#USD
      bestPrice <- cheaperOf(vendorA, vendorB)
      stdout.println(`Cheaper quote (both set): ${bestPrice}`)

      // <? with one unset — returns the set value
      knownQuote <- 199.00#USD
      missingQuote <- Money()
      availableQuote <- cheaperOf(knownQuote, missingQuote)
      stdout.println(`Available quote (one unset): ${availableQuote}`)

      // ============================================================
      // PART 2: :=? GUARDED ASSIGNMENT — sets a variable if unset
      // ============================================================

      // :=? assigns ONLY IF the target is unset
      price <- Money()
      minimumPrice <- 9.99#USD
      price :=? minimumPrice
      stdout.println(`Default price applied: ${price}`)

      // :=? with already-set target — assignment is skipped
      existingPrice <- 49.99#USD
      existingPrice :=? minimumPrice
      stdout.println(`Existing price preserved: ${existingPrice}`)

      // ============================================================
      // PART 3: SAME TYPES, DIFFERENT OPERATIONS
      // ============================================================

      // Both operations work on Date, but do different things:

      // <? picks the earlier of two dates
      dateA <- 2024-11-15
      dateB <- 2024-11-08
      earlierDate <- earlierOf(dateA, dateB)
      stdout.println(`Earlier date: ${earlierDate}`)

      // :=? sets a deadline only if none exists
      deadline <- Date()
      fallbackDate <- 2024-12-31
      deadline :=? fallbackDate
      stdout.println(`Fallback deadline: ${deadline}`)
Other ways to ask this
  • What is the distinction between <? and :=? in EK9?
  • I keep confusing <? coalescing with :=? guarded assignment — show them side by side.
  • In Java I mix up Math.min with null-check assignment. How are these separate in EK9?
  • Show the two operators that look similar but do completely different things.

Coming from another language?

Java conflates these: Math.min(a, b) for comparison vs if (x == null) x = default for assignment — both need null checks. EK9 separates them cleanly: <? for comparison, :=? for conditional assignment. Each handles unset values automatically.

Keywords: contrast, <?, guarded, coalescing, comparison, distinction, assignment, :=?