Chapter 4

Arrays & Maps

Two collections, one philosophy: they hold one type of thing, they grow when asked, and they check your indexes so that being wrong is loud instead of subtle.

Arrays

An array of T has type [T]. Literals use brackets; elements must agree on their type. Arrays grow with push, shrink with pop, and know their len.

func main() -> Int {
    let primes = [2, 3, 5, 7]
    push(primes, 11)
    print(len(primes))        // 5
    print(primes[0])          // 2
    print(pop(primes))        // 11
    return 0
}

Indexing is bounds-checked at runtime. Reading primes[9] ends the program with sure: index 9 is not within 4 — an abort, not a corruption. An empty literal has no elements to learn a type from, so declare it: let xs: [Int] = [].

Iterate with for, by element or by index:

func main() -> Int {
    let names = ["lexer", "parser", "typechecker"]
    for name in names {
        print(name)
    }
    for i in 0..len(names) {
        print(str(i) + ": " + names[i])
    }
    return 0
}

sort(xs) orders an array of Int, Float, or String in place. Arrays nest — [[Int]] is an array of arrays — and may hold structs, in which case deleting the array deletes every struct in it.

Maps

A map from K to V has type {K: V}. Keys are Int or String; values are anything, including other maps. Indexing reads and writes; has asks; delete removes; keys returns an array of keys.

func main() -> Int {
    let ports = {"http": 80, "https": 443}
    ports["ssh"] = 22
    print(ports["https"])         // 443
    print(len(ports))             // 3
    if has(ports, "ftp") {
        print("somehow")
    }
    delete(ports, "http")
    return 0
}

Reading a key that isn't there is not a quiet default — it is sure: that key is not in this map. we checked, and the program is over. Ask has first, or use an if expression:

func main() -> Int {
    let counts: {String: Int} = {}
    let words = split("to be or not to be", " ")
    for w in words {
        counts[w] = if has(counts, w) { counts[w] + 1 } else { 1 }
    }
    let unique = keys(counts)
    sort(unique)
    for w in unique {
        print(w + ": " + str(counts[w]))
    }
    return 0
}

That is the complete word-count program, and it demonstrates the one behavior worth memorizing: keys returns keys in the map's internal order, which is not yours. Sort them if the order matters.

Collections hold references. Putting a string in a map does not copy it — the map holds the same string your variable does. This matters in chapter 7, because when two things hold one value, the question of when that value should be freed becomes a matter of judgment. Sure has judgment.