Improve Documentation for Closures


(Dmitry Lobanov) #1

It is a bit complicated for myself to read documentation about capturing lists and closures.

For example, neither Closures nor capturing lists sections contains a capturing list with assignment.

Consider following complex example and answer one question: What will be printed to console?

enum ClosuresScope {
    class ExampleClass: CustomStringConvertible {
        var item: Int = 0
        func update(item: Int) {
            self.item += item
        }
        var description: String {
            return "self -> \(self.item)"
        }
    }
    struct ExampleStruct {
        var item: Int = 0
        mutating func update(item: Int) {
            self.item += item
        }
    }
    class CapturingAndBlockAttribute {
        func example() {
            let classItem = ExampleClass()
            var structItem = ExampleStruct()
            let closure: () -> (Int) = {
                [unowned internalClass = classItem, internalStruct = structItem] in
                classItem.update(item: 3)
                internalClass.update(item: 20)
                internalStruct.update(item: 5)
                structItem.update(item: 10)
                return classItem.item
            }
            classItem.update(item: 5)
            structItem.update(item: 5)
            _ = closure()
            print("classItem: \(classItem) structItem: \(structItem)")
        }
    }
}

(Kyle Murray) #2

For anywhere you'd like to see improved documentation about language-level constructs like capture lists, the best place to file a bug is https://bugreporter.apple.com

You might find the Capture Lists section in the language reference useful.

If you run the example method:

ClosuresScope.CapturingAndBlockAttribute().example()

You'll get a compiler error about mutating a closure parameter from this line:

internalStruct.update(item: 5)

Is your broader question about the value vs. reference semantics of capture lists? There's some discussion and examples in the section I linked earlier:

The a in the inner scope is initialized with the value of the a in the outer scope when the closure is created, but their values are not connected in any special way. This means that a change to the value of a in the outer scope does not affect the value of a in the inner scope, nor does a change to a inside the closure affect the value of a outside the closure. In contrast, there is only one variable named b —the b in the outer scope—so changes from inside or outside the closure are visible in both places.

This distinction is not visible when the captured variable’s type has reference semantics.