Beware of those lazy global variables

Recently I have had a very humbling and sobering experience with global variables. Don't let them affect your measurements and your judgment.

Can you spot the victim in the following code?

Code
import Foundation

@main
enum ForOrWhileLoop {
    static func main ()  {
        measure (prefix: "T1", f: T1)
        measure (prefix: "T2", f: T2)
        measure (prefix: "T3", f: T3)
        measure (prefix: "T4", f: T4)
        measure (prefix: "T5", f: T5)
    }
}

let M = 1_000_000

let uv: [Int] = .init (unsafeUninitializedCapacity: M) { buffer, initializedCount in
    for i in 0..<M {
        buffer [i] = Int.random(in: 0..<1024)
    }
    initializedCount = M
}

func measure (prefix: String, f: () -> Int) {
    let c = ContinuousClock ()
    let d = c.measure {
        _ = f ()
    }
    print ("M = \(M)", prefix, "took", d)
}

func T1 () -> Int {
    var sum: Int = 0
    for u in uv {
        sum += u
    }
    return sum
}

func T2 () -> Int {
    var sum: Int = 0
    for i in 0..<M {
        sum += uv [i]
    }
    return sum
}

func T3 () -> Int {
    var sum: Int = 0
    var i: Int = 0
    
    while i < M {
        sum += uv [i]
        i += 1
    }
    return sum
}

func T4 () -> Int {
    let sum = uv.reduce (0) { partialResult, u in
        partialResult + u
    }
    return sum
}

func T5 () -> Int {
    var sum: Int = 0
    uv.withUnsafeBufferPointer {
        var i: Int = 0
        while i < M {
            sum += $0 [i]
            i += 1
        }
    }
    return sum
}

If you can't, then head over to this post, and then this post.

1 Like