> On Sep 21, 2016, at 4:01 PM, John Holdsworth via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> My contrived example was a bit flimsy. I’d better unpack the full story. The 
> real
> code I had problems with was based around the following Java instance wrapper:
> 
> open class JNIObject: JNIObjectProtocol {
> 
>     var _javaObject: jobject?
> 
>     open var javaObject: jobject? {
>         get {
>             return _javaObject
>         }
>         set(newValue) {
>             if newValue != _javaObject {
>                 let oldValue = _javaObject
>                 if newValue != nil {
>                     _javaObject = JNI.api.NewGlobalRef( JNI.env, newValue )
>                 }
>                 else {
>                     _javaObject = nil
>                 }
>                 if oldValue != nil {
>                     JNI.api.DeleteGlobalRef( JNI.env, oldValue )
>                 }
>             }
>         }
>     }
> 
>     deinit {
>         javaObject = nil
>     }
> 
> As a result the following transfer of a Java instance always worked:
> 
>     init(imageProducer:ImageProducer) {
>         let supr = CanvasBase()
>         super.init( javaObject: supr.javaObject )
>         image = createImage(imageProducer)
>     }
> 
> But the following only worked for debug compiles:
> 
>     init(imageProducer:ImageProducer) {
>         super.init( javaObject: CanvasBase().javaObject )
>         image = createImage(imageProducer)
>     }
> 
> Felt like a bit of a bear trap is all. Statement scope would avoid problems 
> like this.

You are thinking about this the inverse way. That the first case works is an 
artifact of the optimizer failing to do a good enough job. Future improved ARC 
optimization can cause both to fail.

> 
> John
> 
> 
>> On 21 Sep 2016, at 23:34, Joe Groff <jgr...@apple.com 
>> <mailto:jgr...@apple.com>> wrote:
>> 
>> 
>>> On Sep 21, 2016, at 3:14 PM, Xiaodi Wu via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> 
>>> I haven't used it myself, but is this the use case addressed by 
>>> `withExtendedLifetime(_:_:)`?
>> 
>> Yeah, if you want to vend resources managed by an object to consumers 
>> outside of that object like this, you need to use withExtendedLifetime to 
>> keep the object alive for as long as you're using the resources. A cleaner 
>> way to model this might be to put the class or protocol in control of 
>> handling the I/O to the file handle, instead of vending the file handle 
>> itself, so that the ownership semantics fall out more naturally:
>> 
>> protocol Storage {
>>  func write(bytes: UnsafeRawPointer, count: Int)
>> }
>> 
>> func save(string: String, to: Storage?) {
>>    if let data = string.data(using: String.Encoding.utf8) {
>>        data.withUnsafeBytes {
>>            _ = to?.write(bytes: $0, count: data.count)
>>        }
>>    }
>> }
>> 
>> -Joe
>> 
>>> On Wed, Sep 21, 2016 at 16:54 John Holdsworth via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> 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
>>> 
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution@swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> 
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to