Why does EK9 reject the ? modifier on function parameters?

← Code Quality · Ref: Q827

A parameter in EK9 is always PRESENT: the caller must pass something for it. So declaring a parameter with ? is not needed, and the compiler rejects it.

THE RULE

Parameters cannot use the ? modifier:

  process()
    -> input as String?    // ERROR: E07300
    <- rtn as String: input

THE FIX

Remove the ? modifier:

  process()
    -> input as String     // CORRECT
    <- rtn as String: input

PRESENT IS NOT THE SAME AS SET

E07300 is about the declaration, not the value. A caller may still pass an UNSET value - processInput(String()) runs the body with 'input' present but unset, and here the result comes back unset too (the program below prints 'Result set: false'). So the body must still treat a parameter as possibly unset, with a guard or the ? operator, when that matters.

WHY THIS MATTERS

EK9 pushes for everything to be initialised. A parameter can never be absent, so '?' on its declaration would be false optionality - the possibly-unset case is handled where the value is used.

See Q310 for code quality. See Q126 for function patterns.

Example

defines module qa.quality.null.not.needed

  defines function

    processInput() as pure
      -> input as String
      <- rtn as String: `Processed: ${input}`

  defines program

    NullNotNeededDemo()
      stdout <- Stdout()
      result <- processInput("hello")
      stdout.println(result)

      //A caller CAN pass an unset value: the parameter is present but unset
      missing <- String()
      fromUnset <- processInput(missing)
      stdout.println(`Result set: ${fromUnset?}`)

Common mistakes

E07300 — Function parameters are always provided by the caller, so they are never absent and the ? modifier is not allowed. Remove it - a caller may still pass an unset value, so check with ? or a guard where it matters. See ek9 -h E07300 for details.

Incorrect:

    -> input as String?

Correct:

    -> input as String
Other ways to ask this
  • What is E07300 DECLARED_AS_NULL_NOT_NEEDED?
  • Why can't I declare a parameter as potentially unset in EK9?
  • How does EK9 enforce parameter initialisation?

Coming from another language?

Java: any reference parameter may be null; @Nullable/@NonNull are unenforced annotations. Kotlin: parameters can be nullable with ?. Rust: parameters are always initialised. Go: parameters always have zero values. EK9: parameters are always present — ? modifier not allowed (E07300) — but a caller may pass an unset value.

Keywords: initialised, optional, E07300, unset, null, parameter, declared