> On 18 Nov 2016, at 16:40, Karl <raziel.im+swift-us...@gmail.com> wrote: > > >> On 18 Nov 2016, at 13:05, Adrian Zubarev via swift-users >> <swift-users@swift.org <mailto:swift-users@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@swift.org <mailto:swift-users@swift.org> >> https://lists.swift.org/mailman/listinfo/swift-users >> <https://lists.swift.org/mailman/listinfo/swift-users> > > > This is kind of an invalid/unsafe design IMO; DocumentValues may escape the > scope of the Document and the underlying storage may be deallocated. > > Instead, I’d recommend a function: > > func withDocumentValues<T>(_ invoke: (inout DocumentValues)->T) -> T { > var view = DocumentValues(self) > defer { _fixLifetime(view) }
Oops.. actually, I think this should be: defer { _fixLifetime(self) } > return invoke(&view) > } > > (unfortunately, this isn’t completely safe because somebody could still copy > the DocumentValues from their closure, the same way you can copy the pointer > from String’s withCString, but that’s a limitation of Swift right now) > > CC: John McCall, because I read his suggestion in the thread about contiguous > memory/borrowing that we could have a generalised @noescape. In this example, > you would want the DocumentValues parameter in the closure to be @noescape. > > - Karl
_______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users