Why does EK9 separate variable declaration from assignment?

← Getting Started · Ref: Q968

EK9 separates declaration (<-) from assignment (:=) to prevent accidental variable creation and make variable lifetimes explicit.

THE PROBLEM IN OTHER LANGUAGES:

In Python/JavaScript, x = 5 either creates or reassigns — you can't tell which. This leads to:
- Accidental shadowing (creating a new variable when you meant to update)
- Typo bugs (misspelling a variable name creates a new one silently)
- Unclear lifetime (when was this variable created?)

EK9'S SOLUTION:

  <- means 'I am creating something new'
  := means 'I am updating something that exists'

This makes every variable's birth point explicit in the code.

Many languages (Go, Rust, Ada) also separate declaration from assignment. EK9 uses <- for new variables and := for updates — making every variable's birth point visible in the code.

See Q965 for the full assignment operator guide.

Example

defines module qa.gettingstarted.declvsassign

  defines function

    <?-
      Shows the lifecycle: declare with <-, update with :=.
      EK9 separates declaration (<-) from assignment (:=).
    -?>
    buildGreeting()
      ->
        firstName as String
        lastName as String
      <-
        rtn as String: String()

      // <- creates the variable (declaration)
      fullName <- `${firstName} ${lastName}`

      // := updates the variable (assignment to existing variable)
      fullName := `${fullName}!`

      rtn := fullName

  defines program

    DeclVsAssignDemo()
      stdout <- Stdout()

      // <- declares new variables
      message <- buildGreeting("Steve", "Limb")
      stdout.println(message)

      // := updates existing variable
      message := buildGreeting("Alice", "Smith")
      stdout.println(message)

      // :=? only assigns if currently unset
      optionalName <- String()
      optionalName :=? "Fallback"
      stdout.println(`Optional: ${optionalName}`)

      // :=? has no effect when already set
      optionalName :=? "Ignored"
      stdout.println(`Still: ${optionalName}`)

Common mistakes

E50001 — The first use of a variable must declare it with '<-'; using ':=' on 'message' before it exists means the name does not resolve. See ek9 -h E50001 for details.

Incorrect:

      message := buildGreeting("Steve", "Limb")

Correct:

      message <- buildGreeting("Steve", "Limb")
Other ways to ask this
  • Why can't I just use = for everything in EK9?
  • What's the point of having <- and := as separate operators?
  • Why does EK9 force me to use <- the first time?
  • How is <- different from := in practice?

Coming from another language?

Go separates declaration from reassignment with different operators, just like EK9. Rust uses 'let' keyword for declaration. Python and Java use = for everything. EK9 makes the distinction at the operator level: <- for new, := for update.

Keywords: lifetime, assignment, variable creation, shadowing, declaration