[swift-evolution] Proposal: Closures capture weak by default

ilya ilya.nikokoshev at gmail.com
Tue Dec 8 06:08:03 CST 2015


I don't think this would satisfy the principle of "working as expected",
e.g.:

class Computer {
    func compute() -> Int { ... }
}

func test() {

    let c = Computer()

    // Expected: the closure executes in the background
    dispatch_async(...) {

        let computed = c.compute()
        print(computed)

        let computed2 = c.compute()
        print(computed2)
    }

}

Actual result if the proposal passes: the closure will not compile as c
will be optional.

Moreover, you'll have some beginners who will fix it with

    dispatch_async(...) {

        if let computed = c?.compute() {
            print(computed)
        }

        if let computed2 = c?.compute() {
            print(computed2)
        }
    }

which has entirely different logic, as now any of those situations is
possible:
(1) both computed and computed2 are printed
(2) none of those is printed
(3) only computed is printed

On Tue, Dec 8, 2015 at 14:15 Andrew Bennett via swift-evolution <
swift-evolution at swift.org> wrote:

> From https://swift.org/about/: "The most obvious way to write code should
> also behave in a safe manner."
>
> To this end I think that closures should capture references types weakly
> by default. Pretty much the only way I know of to (easily) create memory
> issues with pure swift is to capture a strong reference in a closure.
>
> I think with consideration when designing asynchronous APIs this could be
> quite painless.
>
> Cases weak may be excluded:
>  * If the closure is @noescape
>  * If the object's lifetime is provably limited to the block
>  * If it's a value type
>
> I think the upsides by far outweigh the downsides.
>
> Upside:
>  * no more surprises
>  * safer code
>
> Downsides:
>  * You may sometimes have to use optional chaining or similar to resolve a
> weak reference.
>  * Beginners need to understand optionals, but they're likely to do so
> before learning blocks.
>  * There's probably a few edge cases I haven't explored, and a few more
> here:
>
> class Test {
>    func doSomething(v: Int) { ... }
>    func async(callback: Int->Void) {
>       doWork { value in
>            callback?(value)
>       }
>    }
> }
>
> self.test = Test()
> self.test.async(test.doSomething) // what is the lifetime
> of test.doSomething?
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151208/c4a76f6e/attachment.html>


More information about the swift-evolution mailing list