When do I use <- and when do I use :=? to set a variable safely?
← Control Flow · Ref: Q1039
They solve different problems:
<- CREATES a new variable. Use it when the variable does not exist yet.
name <- "Alice" creates name, assigns "Alice" if greeting <- getGreeting() creates greeting in this scope, only enters if SET
:=? REASSIGNS an existing variable, but only if it is currently UNSET. Use it when the variable already exists and you want to fill in a missing value without overwriting an existing one.
name <- loadFromConfig() creates name - unset if config has nothing name :=? "default" assigns only if still unset after config
Create it from the first source rather than unset: 'name <- String()' followed by 'name :=? loadFromConfig()' always applies, so the compiler asks for 'name <- loadFromConfig()' (E08097). To declare a variable with no value at all, write 'name as String?' - filling that empty slot is what :=? is for.
Key distinction:
<- is about CREATION. The variable must not exist yet. :=? is about SAFE UPDATE. The variable must already exist. It protects existing values.
Common mistake: using <- when you mean :=?
name <- loadFromConfig() WRONG if name already exists in scope name :=? loadFromConfig() RIGHT — safely fills in if unset
Common mistake: using :=? when you mean <-
name :=? "Alice" WRONG if name does not exist yet name <- "Alice" RIGHT — creates the variable
In guards (if, switch, while):
if name <- getGreeting() declaration guard — creates name, enters if SET if name :=? getGreeting() assign-if-unset — fills name if unset, enters if SET
Example
#!ek9 defines module qa.controlflow.declare.vs.assignifunset defines function loadFromConfig() <- rtn as String: String() //Simulate: config returns unset loadFromEnvironment() <- rtn as String: "env-value" defines program DeclareVsGuardedDemo() stdout <- Stdout() // <- creates a new variable - from the first source (config returns unset, so it starts unset) setting <- loadFromConfig() // :=? fills in from next source (environment returns "env-value") setting :=? loadFromEnvironment() // :=? preserves existing value (already set, so "fallback" is ignored) setting :=? "fallback" stdout.println(`Setting: ${setting}`) // Contrast: <- in a guard creates a NEW variable if greeting <- loadFromEnvironment() stdout.println(`Greeting: ${greeting}`)
Common mistakes
E50001 — Use <- to create a new variable; :=? only reassigns a variable that already exists, so using it first leaves the name unresolved. See ek9 -h E50001 for details.
Incorrect:
setting :=? loadFromConfig()
Correct:
setting <- loadFromConfig()
Other ways to ask this
- What is the difference between <- and :=? in EK9?
- Should I use declaration or assign-if-unset here?
- How do I choose between <- for new variables and :=? for safe reassignment?
Coming from another language?
No other language has this distinction. Python's walrus := creates AND assigns. EK9 separates creation (<-) from safe update (:=?).
Keywords: assign, create, declare, difference, guarded, safe, unset