Why can't I extend List or Dict in EK9?
← Collections and Data Structures · Ref: Q128
EK9 collection types (List, Dict, PriorityQueue, Optional, Result) are closed by default and cannot be extended. This is a deliberate design decision for semantic integrity.
CLOSED BY DESIGN
Attempting to extend List or Dict produces a compile error:
MyList extends List of String Error: not open to be extended
This applies to all built-in generic collection types.
WHY CLOSED
Java's open ArrayList and HashMap are widely considered a design mistake:
Subclassing mixes collection behavior with application logic Fragile base class problem: internal changes break subclasses Liskov substitution violations when overriding methods
Modern languages (Swift, Rust, Kotlin) avoid this pattern.
COMPOSITION ALTERNATIVE
Wrap the collection as a private field:
ValidatedList
items as List of String: List() of String
add(item)
if isValid(item)
items += item
This keeps collection behavior separate from your domain logic.
DELEGATION PATTERN
Expose only the operations that make sense for your domain:
size() <- length items get(index) <- items.getOrDefault(index, "")
Don't expose the full collection API if your type has different semantics.
See Q101 for why types are closed by default. See Q109 for composition over inheritance. See Q45 for List basics. See Q46 for Dict basics. See Q130 for mutating vs non-mutating operators on collections. See Q194 for defining generic classes. See Q212 for composition over inheritance pattern.
Example
defines module qa.collections.closedcollections defines class TaskList items as List of String: List() of String add() -> task as String if task? and not (items contains task) items += task remove() -> task as String items -= task size() as pure <- rtn as Integer: length items all() as pure <- rtn as List of String: items operator $ as pure <- rtn as String: $items override operator ? as pure <- rtn as Boolean: items? defines program ClosedCollectionsDemo() stdout <- Stdout() // === COMPOSITION PATTERN === tasks <- TaskList() tasks.add("Write code") tasks.add("Run tests") tasks.add("Deploy") // Duplicate is rejected by our add logic tasks.add("Run tests") stdout.println(`Tasks (${tasks.size()}): ${tasks}`) // Safe removal tasks.remove("Deploy") stdout.println(`After remove: ${tasks}`) // Get a copy of internal list allTasks <- tasks.all() stdout.println(`All: ${allTasks}`)
Common mistakes
E01073 — EK9 does not have null. The keyword is deliberately excluded. Use the ? operator to check if a variable is set. 'task?' checks tri-state (set/unset), replacing Java-style null checks. See ek9 -h E01073 for details.
Incorrect:
if task <> null
Correct:
if task? and not (items contains task)
E06180 — Class fields are always private in EK9. The 'items' field inside TaskList cannot be accessed directly — this is why composition works. You control the API through public methods like all(). See ek9 -h E06180 for details.
Incorrect:
allTasks <- tasks.items
Correct:
allTasks <- tasks.all()
E50060 — TaskList has no .push() method. The class defines 'add()' as its public API. With composition, you name methods to match your domain. See ek9 -h E50060 for details.
Incorrect:
tasks.push("Write code")
Correct:
tasks.add("Write code")
E50060 — EK9 does not have toString(). Use string interpolation or the $ operator. TaskList defines operator $ for string conversion. See ek9 -h E50060 for details.
Incorrect:
stdout.println(tasks.toString())
Correct:
stdout.println(`Tasks (${tasks.size()}): ${tasks}`)
Other ways to ask this
- Why are collection types closed in EK9?
- How do I add custom behavior to a List in EK9?
- What is the alternative to subclassing collections in EK9?
Coming from another language?
Java: ArrayList and HashMap are open (considered design mistake). Python: can extend list and dict freely (mixin pattern). JavaScript: can extend Array. Rust: no inheritance, composition required. Go: no inheritance, embed structs. Kotlin: classes final by default (like EK9). EK9: all collection types closed, use composition and delegation instead of inheritance.
Keywords: list, extend, collection, migrate, dict, closed, wrap, delegation, sealed, exhaustive, design, data-structure, inherit, composition