What does EK9 error E04050 mean when I declare a class field and how do I fix it?
← Classes and OOP · Ref: Q1282
E04050 fires when you use the '<-' declaration form for a class field with an expression the compiler cannot resolve to a simple type during early phase processing. In practice the usual cause is writing the is-set operator '?' at the end of a parameterised constructor call, like 'names <- List() of String?'. That is NOT a nullable-type marker in EK9 — it is the is-set operator being invoked on the newly-created List, which produces a Boolean, which cannot be the type of a List field. The compiler reports E04050 because type inference cannot reconcile 'List of String' with 'Boolean'.
THE FIX
Drop the trailing '?' and use the simple parameterised constructor form:
names <- List() of String
This declares a class field 'names' of type 'List of String' and initialises it to an empty list. The List type is always 'set' when created, so you do not need an is-set check on it.
WHY THIS CATCHES PEOPLE
C#, Kotlin, TypeScript, and Swift all use a trailing '?' on a type to mean 'nullable'. EK9 has no null. '?' in EK9 is the is-set operator — it is a unary postfix method that returns a Boolean telling you whether the object it is called on currently holds a meaningful value. Writing 'List() of String?' therefore means 'construct an empty List, then ask whether it is set' — not 'a List field that might be unset'.
FIELD DECLARATION FORMS THAT WORK
names <- List() of String // empty List of String scores <- Dict() of (String, Integer) // empty Dict tags <- ["alpha", "beta", "gamma"] // List literal (type inferred) counters as Integer: 0 // explicit type + initial value label as String: "default" // explicit type + literal
FIELD DECLARATION FORMS THAT FAIL WITH E04050
names <- List() of String? // '?' invoked on the List result <- compute() + 10 // arithmetic choice <- flag ? valueA : valueB // no ternary in EK9 anyway
WHEN IN DOUBT USE EXPLICIT TYPING
If the field's type is at all complex, abandon '<-' and use 'name as Type: value'. The explicit form tells the compiler the type up front and lets full expression processing happen later:
total as Float: price * quantity // explicit type survives complex expr
See Q585 for field initialisation and constructor delegation. See Q104 for why EK9 requires explicit constructors on some uninitialised fields.
Example
defines module qa.classesandoop.e04050fieldfix defines class UniqueNames names <- List() of String add() -> name as String if not names contains name names += name count() as pure <- rtn as Integer: length names override operator ? as pure <- rtn as Boolean: names? operator $ as pure <- rtn as String: `UniqueNames(${length names})` defines program E04050FieldFixDemo() stdout <- Stdout() names <- UniqueNames() names.add("Alice") names.add("Bob") names.add("Alice") stdout.println($names)
Common mistakes
E04050 — The trailing '?' invokes the is-set operator on the constructed List, producing a Boolean. Type inference cannot reconcile that with a List-of-String field. Drop the '?' — EK9 has no nullable types, and the List itself is always set once created.
Incorrect:
names <- List() of String?
Correct:
names <- List() of String
Other ways to ask this
- I'm getting E04050 'not expecting complex expression' on a class field — what's wrong?
- Why does 'names <- List() of String?' fail to compile in a class body?
- How do I initialize a List field in an EK9 class without E04050?
- The compiler says my field declaration needs a simple aggregate — how do I fix it?
Coming from another language?
C#/Kotlin: 'List<string>?' means nullable List — a valid type. EK9: 'List() of String?' means 'call ? on the newly-created List' — produces Boolean, fails type inference. If you want a field that might be unset in EK9, the collection itself is always set (empty List IS valid); the question 'is this field populated' is answered by '?' on the field at the point you check it, not in the type declaration.
Keywords: type inference, E04050, complex expression, field declaration, nullable type, List, is-set operator