In my previous post: “Unexpected behaviour with Swift’s [Any]”, I declared a nested array of integers as:

let a : [Any] = [1,2,[3],[4,[5,6]],[[7]], 8]

Using Any feels like a code smell; by using Any I’m effectively saying, “ignore all the type-checking the compiler performs, instead I’ll rely on my own knowledge of the types”. Experience shows I am not as knowledgable as the compiler, especially after some time has elapsed and I’m trying to add a new feature… That said, my intent wasn’t to suppress the compiler’s type checking, I simply didn’t know how to express a heterogeneous array without resorting to Any. However I’ve been learning Haskell where the way to express such heterogeneous arrays is by using a sum type. In Swift sum types are defined using enums. Let’s start by defining an enum, which will hold either Int or Array values:

enum IntOrArray {
    case intValue(Int)
    case arrayValue([IntOrArray])
}

the array:

let a : [Any] = [1,2,[3],[4,[5,6]],[[7]], 8]

can then be expressed in an equivalent type-safe way as:

let a : [IntOrArray] = [.intValue(1), .intValue(2), .arrayValue([.intValue(4), .arrayValue([.intValue(5), .intValue(6)])]), .arrayValue([.arrayValue([.intValue(7)])]), .intValue(8)]

A process function is easy to write without resorting to the horrible hacks documented my previous post:

func process(anArray : [IntOrArray]) {
    for element in anArray {
        switch(element) {
        case .intValue(let intValue):
            print("intValue = \(intValue)")
        case .arrayValue(let arrayValue):
            process(arrayValue)
        }
    }
}

process(a)

It’s also fun to write a flatten function without any mutable variables:

func flatten(anArray : [IntOrArray]) -> [Int] {
    return anArray.flatMap (flattenAnElement)
}

func flattenAnElement (element : IntOrArray) -> [Int] {
    switch element {
    case .intValue(let intValue):
        return [intValue]

    case .arrayValue(let arrayValue):
        return flatten(arrayValue)
    }
}

flatten(a) // [1,2,4,5,6,7,8]

Swift’s enumerations with associated values are a language feature which can often be used instead of class hierarchies, they benefit from being value types and frequently express the intent of the code much more succinctly than a class based alternative.

A playground containing the code in this post can be downloaded here