How do I find the first matching item in a list without break or return in EK9?

← Control Flow Without break/continue/return · Ref: Q1267

EK9 has no break or return. To find the first matching item, declare the return variable with a default (unset) value, then use the guarded assignment operator ':=?' inside the loop. ':=?' only assigns when the target is currently unset — so the first match sets it and all subsequent matches are ignored.

PATTERN

  findFirst()
    -> items as List of String
    -> searchTerm as String
    <- rtn as String: String()
    for item in items
      if item contains searchTerm
        rtn :=? item

HOW IT WORKS

1. rtn starts as String() — unset
2. Loop iterates every item (no early exit)
3. First match: rtn :=? item assigns because rtn is unset
4. Second match: rtn :=? item is SKIPPED because rtn is already set
5. After the loop, rtn holds the first match (or remains unset)

CALLER PATTERN

Use a guard expression to check if a match was found:

  if found <- findFirst(names, searchFor)
    stdout.println(found)
  else
    stdout.println("No match")

See Q1239 for the stream pipeline alternative (filter + head). See Q985 for :=? basics.

Example

defines module qa.without.findfirstguard

  defines function

    findFirstContaining() as pure
      ->
        items as List of String
        searchTerm as String
      <- rtn as String: String()
      for item in items
        if item?
          if item contains searchTerm
            rtn :=? item

  defines program

    FindFirstDemo()
      stdout <- Stdout()

      names <- List() of String
      names += "Java"
      names += "EK9-Language"
      names += "Python"
      names += "EK9-Compiler"

      searchFor <- "EK9"

      if found <- findFirstContaining(names, searchFor)
        stdout.println(`First match: ${found}`)
      else
        stdout.println("No match found")

      if noMatch <- findFirstContaining(names, "Rust")
        stdout.println(`Found: ${noMatch}`)
      else
        stdout.println("No Rust match — correct")

Common mistakes

E01072 — EK9 has no return statement. Use a return variable declaration (rtn as Type: default) and :=? guarded assignment to set it once. See ek9 -h E01072 for details.

Incorrect:

        return item

Correct:

        rtn :=? item

E01070 — EK9 has no break statement. The :=? operator achieves the same effect — once rtn is set, further :=? assignments are ignored. See ek9 -h E01070 for details.

Incorrect:

        break

Correct:

        rtn :=? item
Other ways to ask this
  • Write a find-first function using guarded assignment :=? in a for loop.
  • How does :=? help me stop at the first match in EK9?
  • Show me the EK9 pattern for returning the first item that satisfies a condition.
  • In Java I'd use break after finding the first match — what does EK9 use?

Coming from another language?

Java: for-loop with break on first match. Python: next(x for x in items if condition, default). Kotlin: items.firstOrNull { condition }. Go: for-range with break. Rust: items.iter().find(|x| condition). EK9: rtn :=? match inside a for loop — no break, no return, the guard operator handles it.

Keywords: first match, guard, loop, no break, no return, :=?, find-first, guarded assignment