[swift-evolution] Should Swift apply "statement scope" for ARC

John Holdsworth mac at johnholdsworth.com
Wed Sep 21 16:53:59 CDT 2016


Hi,

For complex statements in C++ any temporary instances created in the course
of an expression have their lifetime extended to the completion of the current
statement after which they are all deallocated en masse. This makes certain
types of language usage possible and easier to reason with.

I’m bringing this up as I had a problem with some code crashing only when
compiled with release configuration and the problem could have been avoided
if Swift deferred deallocation to the end of a statement. While Swift’s ARC policy
is consistent in itself this seems to be a particular problem interfacing between
language/reference counting systems. My problem code was a Java-Swift Bridge.

A contrived example:

import Foundation

protocol Storage {
    var fp: UnsafeMutablePointer<FILE> { get }
}

class FileStorage: Storage {

    let fp: UnsafeMutablePointer<FILE>

    init?(path: String, mode: String = "w") {
        print("Opening")
        let fp = fopen(path, mode)
        if fp == nil {
            return nil
        }
        self.fp = fp!
    }

    deinit {
        print("Closing")
        fclose(fp)
    }
}

func save(string: String, to: Storage?) {
    if let data = string.data(using: String.Encoding.utf8) {
        print("Saving1")
        if let fp = to?.fp {
            print("Saving2")
            data.withUnsafeBytes {
                _ = fwrite($0, 1, data.count, fp)
            }
            print("Saving3")
        }
    }
}

save(string: "Hello World\n", to: FileStorage(path: "/tmp/a.txt"))


In debug configuration is prints:
Opening
Saving1
Saving2
Saving3
Closing

Whereas in release configuration it prints:
Opening
Saving1
Closing <!!!
Saving2
Saving3

The optimiser is vigorously deallocating objects when they are no longer referenced regardless
of whether an variable referencing it is still in scope (In fairness this particular problem only occurs
for Optional augments of Protocols) but this behaviour seems to be implicit in the current language
spec. The alternative is to retain arguments themselves as I believe they are in Objective-C ARC.

This would have been avoided if the temporary FileStorage instance has been considered to have
a lifetime up to the end of the statement calling function save() and hence the duration of the call.
This needed increase ARC overhead in any way. Just alter the timing of it to be more conservative.

John

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160921/0a1fdee7/attachment.html>


More information about the swift-evolution mailing list