Select the earlier time from two shift starts, and which one wins when they are equal?

← Operators and Expressions · Ref: Q1218

The <? coalescing operator returns the lesser of two values, handling unset gracefully.

  earlierStart() as pure
    ->
      left as Time
      right as Time
    <- rtn as Time: left <? right

If both times are set and different, <? returns the earlier one. If one is unset, it returns the set one. If both are unset, the result is unset.

When the two times are equal (<=> gives 0), <? returns the LEFT operand. For Time values equal means identical, so you cannot tell; it matters when <=> ties on objects that differ, such as a record whose <=> compares one field. To get the right operand on a tie, swap the operands: right <? left. There is no separate 'or equal' form - the inclusive operators were removed (E01095) because this is the one tie rule for <? and >?. See Q1227 for both operators side by side.

Do not confuse any coalescing operator with :=? (assign-if-unset). See Q1226 for the contrast.

Example

#!ek9
defines module qa.operators.coalescetie.time

  defines function

    earlierStart() as pure
      ->
        left as Time
        right as Time
      <- rtn as Time: left <? right

  defines program

    CoalesceTieTimeDemo()
      stdout <- Stdout()

      // === BOTH SHIFTS SCHEDULED — returns the earlier ===

      morningShift <- 06:00
      dayShift <- 09:00
      firstStart <- earlierStart(morningShift, dayShift)
      stdout.println(`First shift starts: ${firstStart}`)

      // === EQUAL TIMES — returns the shared time (the left operand) ===

      shiftA <- 08:00
      shiftB <- 08:00
      sameStart <- earlierStart(shiftA, shiftB)
      stdout.println(`Both start at: ${sameStart}`)

      // === ONE SHIFT UNSCHEDULED — returns the scheduled one ===

      scheduledShift <- 07:30
      unscheduledShift <- Time()
      onlyShift <- earlierStart(scheduledShift, unscheduledShift)
      stdout.println(`Scheduled shift: ${onlyShift}`)

      // === BOTH UNSCHEDULED — result is unset ===

      missingShift <- Time()
      noShiftB <- Time()
      bothMissing <- earlierStart(missingShift, noShiftB)
      if bothMissing?
        stdout.println(`Shift: ${bothMissing}`)
      else
        stdout.println("No shifts scheduled")

Common mistakes

E50030 — '<=' is a comparison that yields Boolean, so assigning 'left <= right' to a Time return is a type mismatch; use the coalescing '<?' which returns the lesser Time (the left one on a tie) and handles unset values. See ek9 -h E50030 for details.

Incorrect:

<- rtn as Time: left <= right

Correct:

<- rtn as Time: left <? right
Other ways to ask this
  • How do I find the lesser of two Time values when one shift might be unscheduled?
  • Two shifts have start times but one could be empty — pick the earlier time.
  • In Java I'd need null checks before comparing with isBefore or equals. What does EK9 use?
  • Migrating from Python where I use min() for times — what does EK9's null-safe minimum return when the two are equal?

Coming from another language?

Java: a == null ? b : b == null ? a : !a.isAfter(b) ? a : b. Python: min(a, b) returns the first of equal values, as <? does. Kotlin: listOfNotNull(a, b).minOrNull(). EK9: left <? right — one operator handles all cases including equality, and the left operand wins a tie.

Keywords: <?, coalescing, earlier, equal, minimum, schedule, shift, tie, time