Show me how to use :=? on a custom class field — give me a worked example where a UserSession class has a sessionToken that is set on first login and never overwritten.
← Operators and Expressions · Ref: Q1266
The :=? guarded assignment works on class fields just as it does on local variables. It is the natural way to implement set-once fields without writing manual 'is this set?' checks. (For data-only carriers without behaviour, use a record — but records cannot have methods, so this example uses a class because it needs a captureToken method.)
USERSESSION CLASS WITH SET-ONCE TOKEN
UserSession
userName as String: String()
sessionToken as String: String()
UserSession()
-> userName as String
this.userName :=: userName
captureToken()
-> token as String
sessionToken :=? token
default operator ?
The captureToken method uses :=? on the field. The first call sets sessionToken. Every subsequent call is silently ignored — the original token is preserved.
USAGE
session <- UserSession("alice")
// First login captures the token session.captureToken("abc-123-first") stdout.println(`after first login: ${session.currentToken()}`)
// Subsequent logins do NOT replace the token session.captureToken("xyz-456-second") session.captureToken("def-789-third") stdout.println(`after more logins: ${session.currentToken()}`)
The sessionToken stays as 'abc-123-first' regardless of how many times captureToken is called.
WHY THIS IS BETTER THAN MANUAL CHECKS
You could write the same logic with an if-check:
captureToken()
-> token as String
if not sessionToken?
sessionToken: token
This works but is verbose and easy to get backwards. The :=? operator does the right thing in one symbol with no risk of missing the negation.
WHEN TO USE GUARDED ASSIGNMENT ON FIELDS
- Authentication tokens captured on first login
- Origin URLs captured on first redirect
- Created-at timestamps that should never change
- Cached computed values that should be set once
- Configuration that loads on first access
In all cases, the goal is 'first value wins, later values ignored'. :=? is the right tool.
See Q1263 for String guarded assignment. See Q1264 for Integer. See Q1265 for Date. See Q1226 for the contrast between :=? and <?.
Example
defines module qa.operators.guardedassignrecord defines class UserSession userName as String: String() sessionToken as String: String() UserSession() -> name as String this.userName :=: name captureToken() -> token as String sessionToken :=? token currentToken() as pure <- rtn as String: sessionToken default operator ? defines program GuardedAssignRecordDemo() stdout <- Stdout() session <- UserSession("alice") session.captureToken("abc-123-first") stdout.println(`after first login: ${session.currentToken()}`) session.captureToken("xyz-456-second") session.captureToken("def-789-third") stdout.println(`after more logins: ${session.currentToken()}`)
Common mistakes
E50060 — String does not have a guardedSet method. The :=? operator is the correct way to perform guarded assignment — it assigns only when the field is unset. See ek9 -h E50060 for details.
Incorrect:
sessionToken.guardedSet(token)
Correct:
sessionToken :=? token
Other ways to ask this
- How does :=? work inside a record method that sets a field once?
- Give me a UserSession example using guarded assignment on a token field.
- Use :=? on a custom record field for set-once semantics.
- Show me a method that initialises a record field with :=? only when unset.
Coming from another language?
Java: if (sessionToken == null) sessionToken = token; — verbose. Kotlin: sessionToken = sessionToken ?: token — also works, but reassigns. Rust: sessionToken.get_or_insert(token); — standard library helper. Python: if self.sessionToken is None: self.sessionToken = token. EK9: sessionToken :=? token — single operator, in-place, idempotent.
Keywords: record field, first value wins, UserSession, :=?, guarded assignment, session token, set once