[swift-users] Problem with mutable views and COW

Adrian Zubarev adrian.zubarev at devandartist.com
Fri Nov 18 08:04:53 CST 2016


This doesn’t make any sense.

Somewhere from the Swift book:

Weak and unowned references enable one instance in a reference cycle to refer to the other instance without keeping a strong hold on it. The instances can then refer to each other without creating a strong reference cycle.
From the sdlib of the function isKnownUniquelyReferenced:

Returns a Boolean value indicating whether the given object is a class instance known to have a single strong reference.
unowned doesn’t increase the reference count, so the view in the examples I showed should have no strong reference to that class instance. The only strong reference that exists is from Document. So why exactly is the result of the second isKnownUniquelyReferenced call false again?



-- 
Adrian Zubarev
Sent with Airmail

Am 18. November 2016 um 14:50:57, Zhao Xin (owenzx at gmail.com) schrieb:

>Why is the second check false, even if the property is marked as unowned for the view?

Please search the mailing list, this is not the first time it comes as a new question. Shortly speaking, it is `false` only because you used `unowned`. If you you can grantee it always exists. Just use it directly, this is what `unowned` for. If you can't grantee that. You should use `weak` and check it with `if let` or `if foo == nil`

Zhaoxin


On Fri, Nov 18, 2016 at 8:05 PM, Adrian Zubarev via swift-users <swift-users at swift.org> wrote:
Hi there,

I just can’t get my head around mutable views and COW.

Here is a small example:

final class Storage {
      
    var keys: [String] = []
    var values: [Int] = []
}

public struct Document {
      
    var _storageReference: Storage
      
    public init() {
          
        self._storageReference = Storage()
    }
      
    public init(_ values: DocumentValues) {
          
        self._storageReference = values._storageReference
    }
      
    public var values: DocumentValues {
          
        get { return DocumentValues(self) }
          
        set { self = Document(newValue) }
    }
}

public struct DocumentValues : MutableCollection {
      
    unowned var _storageReference: Storage
      
    init(_ document: Document) {
          
        self._storageReference = document._storageReference
    }
      
    public var startIndex: Int {
          
        return self._storageReference.keys.startIndex
    }
      
    public var endIndex: Int {
          
        return self._storageReference.keys.endIndex
    }
      
    public func index(after i: Int) -> Int {
          
        return self._storageReference.keys.index(after: i)
    }
      
    public subscript(position: Int) -> Int {
          
        get { return _storageReference.values[position] }
          
        set { self._storageReference.values[position] = newValue } // That will break COW
    }
}
First of all the _storageReference property is unowned because I wanted to check the following:

var document = Document()

print(CFGetRetainCount(document._storageReference)) //=> 2
print(isKnownUniquelyReferenced(&document._storageReference)) // true

var values = document.values

print(CFGetRetainCount(values._storageReference)) //=> 2
print(isKnownUniquelyReferenced(&values._storageReference)) // false
Why is the second check false, even if the property is marked as unowned for the view?

Next up, I don’t have an idea how to correctly COW optimize this view. Assume the following scenario:

Scenario A:

var document = Document()

// just assume we already added some values and can mutate safely on a given index
// mutation in place
document.values[0] = 10   
VS:

Scenario B:

var document = Document()

let copy = document

// just assume we already added some values and can mutate safely on a given index
// mutation in place
document.values[0] = 10 // <--- this should only mutate `document` but not `copy`
We could change the subscript setter on the mutable view like this:

set {
              
    if !isKnownUniquelyReferenced(&self._storageReference) {
                  
        self._storageReference = ... // clone
    }
    self._storageReference.values[position] = newValue
}
There is only one problem here. We’d end up cloning the storage every time, because as shown in the very first example, even with unowned the function isKnownUniquelyReferenced will return false for scenario A.

Any suggestions?

PS: In general I also wouldn’t want to use unowned because the view should be able to outlive it’s parent.



-- 
Adrian Zubarev
Sent with Airmail

_______________________________________________
swift-users mailing list
swift-users at swift.org
https://lists.swift.org/mailman/listinfo/swift-users


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20161118/ef56e69d/attachment.html>


More information about the swift-users mailing list