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