Why does E07175 fire on my generic class with a 'T?' field and a default constructor?
← Generics · Ref: Q1346
A generic field declared 'item as T?' is uninitialised at declaration. If the only no-argument constructor is the compiler-generated 'default Container()', that constructor leaves 'item' NULL — and any later use (for example the synthetic '?' operator reading 'item?') would dereference null. This is the billion-dollar mistake, so EK9 rejects it at compile time with E07175.
Error : E07175: 'Container' ...: default constructor must be 'private' when uninitialised properties exist
THE IDIOMATIC FIX: give the field an unset T()
Replace 'default Container()' with a real no-arg constructor that first-initialises the field to an unset T(). The field is then present-but-unset (never null):
Container of type T item as T? Container() as pure item :=? T() // present-but-unset, never null Container() as pure -> initial as T item :=? initial
WHY ':=?' (not ':=' or ':')
In a pure constructor ':=' is forbidden (E08100). The guarded ':=?' assigns only if the field is unset, which is exactly 'first-initialise to an unset value'.
IF T() IS NOT AVAILABLE
When T may be abstract, may hold a function, or has no public no-arg constructor, you cannot call T(). Then declare 'default private Container()' instead - external code cannot create an empty one, and callers must use the inferred constructor with a value.
See Q1347 for creating empty instances. See Q1348 for the T() limits. See Q645 for the private no-arg escape hatch.
Example
defines module qa.genericsdeep.optionalfieldnullsafety defines class Container of type T item as T? Container() as pure item :=? T() Container() as pure -> initial as T item :=? initial hasItem() as pure <- rtn as Boolean: item? default operator ? defines program OptionalFieldDemo() stdout <- Stdout() emptyOne <- Container() of String stdout.println(`emptyOne hasItem: ${emptyOne.hasItem()}`) filled <- Container("hello") stdout.println(`filled hasItem: ${filled.hasItem()}`)
Common mistakes
E07175 — A generic 'default Container()' leaves a 'T?' field null. Give the field an unset T() in the no-arg constructor (item :=? T()), or declare the default private. See ek9 -h E07175 for details.
Incorrect:
default Container() as pure
Correct:
Container() as pure item :=? T()
Other ways to ask this
- My generic 'default Container() as pure' is rejected — why?
- How do I stop a generic's optional field being null?
- E07175 default constructor must be private when uninitialised properties exist — on a generic
Coming from another language?
Java/Kotlin: a generic field T is null until assigned; reading it risks NullPointerException at runtime. Rust: Option<T> forces an explicit None. EK9: a 'T?' field must be made present-but-unset (item :=? T()) or the type must forbid empty construction (default private) - the null is eliminated at compile time, not deferred to runtime.
Keywords: default, uninitialised, T?, field, E07175, null, generic, optional, constructor, guarded-assignment, present-but-unset