How does the List type work in EK9?
← Getting Started · Ref: Q45
EK9 has a generic List type for ordered, indexable collections. Lists use square bracket literal syntax [1, 2, 3] and the generic declaration List of T.
LIST CREATION
Four ways to create lists:
numbers <- [1, 2, 3, 4, 5] literal syntax, compiler infers List of Integer emptyList <- List() of String typed empty list single <- List(42) single-element construction fruits <- [ "apple", "banana" ] multi-line literal for readability
GENERIC SYNTAX
EK9 uses 'of' instead of angle brackets: List of String, List of Integer. No <> needed.
ADDING ELEMENTS
+= mutates the list in place:
names += "Dave" appends Dave names += ["Eve", "Frank"] appends both
+ creates a new list (original unchanged):
moreNames <- names + "Grace"
REMOVING ELEMENTS
-= mutates the list:
fruits -= "banana" removes banana
- creates a new list without the element:
without <- fruits - "banana"
ACCESSING ELEMENTS
Safe element access with getOrDefault:
first <- numbers.getOrDefault(0, 0) first element last <- numbers.getOrDefault(length numbers - 1, 0) last element
getOrDefault always returns a value: either the element at the index, or the provided default. No exceptions, no unset results.
LENGTH AND EMPTY CHECK
len <- length numbers number of elements isEmpty <- numbers is empty true if no elements
ITERATION
for fruit in fruits stdout.println(fruit)
EMPTY LIST IS SET
CRITICAL: An empty list IS set. Creating List() of String gives you a valid, set, empty list. Empty is not the same as unset.
See Q88 for operations (contains, reverse, copy, merge, comparison). See Q89 for stream pipelines (filter, map, collect). See Q37 for string interpolation with lists. See Q39 for integers used in list indexing. See Q120 for sorting lists. See Q125 for head/tail/skip to limit streams. See Q130 for mutating vs non-mutating operators. See Q131 for Python comprehension equivalents. See Q180 for list add. See Q183 for list first and last.
Example
defines module qa.list defines function isEven() as pure -> num as Integer <- rtn as Boolean: num mod 2 == 0 intToString() as pure -> num as Integer <- rtn as String: $num defines program ListDemo() stdout <- Stdout() // === LIST CREATION === // Literal syntax — compiler infers List of Integer numbers <- [1, 2, 3, 4, 5] stdout.println(`Numbers: ${numbers}`) // Typed empty list emptyList <- List() of String stdout.println(`Empty: ${emptyList}`) // Single-element construction single <- List(42) stdout.println(`Single: ${single}`) // Multi-line literal fruits <- [ "apple", "banana", "cherry" ] stdout.println(`Fruits: ${fruits}`) // === ADDING ELEMENTS === names <- List() of String names += "Alice" names += "Bob" names += "Charlie" stdout.println(`After +=: ${names}`) // + creates a new list (original unchanged) moreNames <- names + "Dave" stdout.println(`Original: ${names}`) stdout.println(`With Dave: ${moreNames}`) // === REMOVING ELEMENTS === without <- fruits - "banana" stdout.println(`Without banana: ${without}`) fruits -= "cherry" stdout.println(`After -=: ${fruits}`) // === ACCESSING ELEMENTS === first <- numbers.getOrDefault(0, 0) last <- numbers.getOrDefault(length numbers - 1, 0) stdout.println(`First: ${first}, Last: ${last}`) third <- numbers.getOrDefault(2, 0) stdout.println(`Index 2: ${third}`) // === LENGTH AND EMPTY === lenNumbers <- length numbers stdout.println(`Length: ${lenNumbers}`) numbersEmpty <- numbers is empty stdout.println(`Numbers empty: ${numbersEmpty}`) listEmpty <- emptyList is empty stdout.println(`Empty list empty: ${listEmpty}`) // === BASIC ITERATION === for fruit in fruits stdout.println(`Fruit: ${fruit}`) // === EMPTY LIST IS SET === require emptyList? require emptyList is empty stdout.println(`Empty list isSet: ${emptyList?}`)
Common mistakes
E06020 — Generic types like List only take the number of parameters that actually parameterize them
Incorrect:
numbers <- List(1, 2, 3, 4, 5)
Correct:
numbers <- [1, 2, 3, 4, 5]
E06010 — The generic type must be parameterized with a type
Incorrect:
emptyList <- List()
Correct:
emptyList <- List() of String
Other ways to ask this
- How do I create and use lists in EK9?
- What is the literal syntax for lists in EK9?
- How do I add and remove items from a list in EK9?
Coming from another language?
Java: ArrayList<T> with verbose generics, no literal syntax (List.of() since Java 9 but immutable). Python: built-in list with [] literal, no static type safety. JavaScript: Array with [] literal, no type safety. Rust: Vec<T> with vec![] macro. Go: slices with make()/append(), no generics until Go 1.18. Kotlin: listOf()/mutableListOf(). EK9: [1, 2, 3] literal, List of T generic (no angle brackets), getOrDefault for safe access, += and + for adding, -= and - for removing.
Keywords: iterate, getOrDefault, list, beginner, for, generic, remove, array, collection, add, intro, migrate, start, length, literal, empty, first