Why does AI generate getters and setters in EK9?
← What AI Gets Wrong About EK9 · Ref: Q280
AI models trained on Java generate getName(), setName(), getValue(), isActive() patterns. Nothing is syntactically wrong with these names in EK9, but they violate EK9 conventions and miss the deeper design philosophy.
THE AI MISTAKE
AI generates Java bean methods: getName(), setName(value), getContent(), isActive(). EK9 does not follow this naming convention.
EK9 ACCESSOR CONVENTION
Use bare noun or verb names:
content() not getContent() keys() not getKeys() hue() not getHue() trim() not getTrim()
EK9 SETTER ALTERNATIVE
Use bare noun with parameter or 'with' prefix:
content(newContent) not setContent(newContent) withContent(newContent) for returning a modified copy
THE DEEPER ISSUE
Get and set patterns encourage breaking information hiding. You should be interested in a class's BEHAVIOR, not its internal state. Classes and components should keep internal state private and expose operations that make sense in the domain.
EXTERNAL STATE REPRESENTATION
If external state is needed, return a RECORD with copies of an external representation, not copies of internal state variables. The record is a deliberate public-facing view, decoupled from internals. If the internal structure changes, the record stays stable.
OPERATORS NOT GETTERS
For standard conversions, use operators:
$ for string representation (replaces toString/getName patterns) $$ for JSON representation ? for state checking (replaces isActive/isValid patterns)
ONLY ENUMERATIONS HAVE AUTOMATIC OPERATORS
Only enumerations have full automatic operator generation. Records and classes can use 'default operator' to opt in, but this is explicit, not automatic.
See Q96 for classes. See Q98 for records. See Q238 for operator overview. See Q281 for verifying AI code.
Example
defines module qa.ai.mistakes.getterssetters defines record // Record as external state representation AccountSummary holder as String: String() balance as Float: Float() AccountSummary() as pure -> theHolder as String theBalance as Float holder :=? theHolder balance :=? theBalance default operator defines class // Class exposes BEHAVIOR, not internal state BankAccount ownerName as String: String() currentBalance as Float: Float() isOpen as Boolean: false BankAccount() -> initialOwner as String initialBalance as Float ownerName: initialOwner currentBalance: initialBalance isOpen: true // Bare noun accessor — NOT getOwnerName() owner() as pure <- rtn as String: String(ownerName) // Behavior method — NOT setBalance() deposit() -> amount as Float if amount > 0.0 and isOpen currentBalance: currentBalance + amount withdraw() -> amount as Float <- success as Boolean: false if amount > 0.0 and amount <= currentBalance and isOpen currentBalance: currentBalance - amount success: true closeAccount() isOpen: false // Return a RECORD as external state view summary() as pure <- rtn as AccountSummary: AccountSummary(ownerName, currentBalance) // $ operator replaces toString() operator $ as pure <- rtn as String: `${ownerName}: ${currentBalance}` // ? operator replaces isActive() override operator ? as pure <- rtn as Boolean: ownerName? and isOpen defines program GetterSetterDemo() stdout <- Stdout() account <- BankAccount("Alice", 1000.0) // === BARE NOUN ACCESSOR — NOT getName() === stdout.println(`Owner: ${account.owner()}`) // === BEHAVIOR METHODS — NOT setBalance() === account.deposit(500.0) stdout.println(`After deposit: ${account}`) if ok <- account.withdraw(200.0) stdout.println(`Withdrew 200: ${account}`) // === RECORD AS EXTERNAL STATE VIEW === view <- account.summary() stdout.println(`Summary: ${view}`) // === ? OPERATOR REPLACES isActive() === stdout.println(`Account active: ${account?}`) account.closeAccount() stdout.println(`After close, active: ${account?}`)
Common mistakes
E50001 — Renaming the variable means later references to 'account' become unresolved, triggering E50001. Variable names must be consistent. See ek9 -h E50001 for details.
Incorrect:
accountXYZ <- BankAccount("Alice", 1000.0)
Correct:
account <- BankAccount("Alice", 1000.0)
E50001 — Renaming the variable means later references to 'view' become unresolved, triggering E50001. Variable names must be consistent. See ek9 -h E50001 for details.
Incorrect:
viewXYZ <- account.summary()
Correct:
view <- account.summary()
Other ways to ask this
- Why does AI use getName() and setName() in EK9?
- What is the EK9 convention for accessors?
- How does EK9 handle information hiding without getters?
Coming from another language?
Java: JavaBean convention (getName/setName), IDE generates getters/setters, Lombok @Data generates them. Python: @property decorator, direct attribute access common. Rust: no getter convention, pub fields or methods. Go: exported fields (uppercase) or accessor methods. Kotlin: properties with get/set, data classes auto-generate. C#: properties with get/set accessors. EK9: bare noun accessors (content() not getContent()), operators for standard conversions ($ for string, ? for state), expose behavior not state, records for external state representation.
Keywords: hallucination, setter, property, encapsulation, hiding, getter, pitfall, common-error, migrate, field, behavior, information, wrong, accessor, bean, ai, mistake