[swift-users] Problem with mutable views and COW
Zhao Xin
owenzx at gmail.com
Fri Nov 18 09:05:03 CST 2016
protocol Copyable {
func copy() -> Self
}
final class Storage:Copyable {
var keys: [String] = []
var values: [Int] = []
func copy() -> Storage {
let s = Storage()
s.keys = keys
s.values = values
return s
}
}
public struct Document:Copyable {
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 func copy() -> Document {
var d = Document()
d._storageReference = _storageReference.copy()
return d
}
}
var document = Document()
let copy = document.copy()
// just assume we already added some values and can mutate safely on a
given index
// mutation in place
document.values[0] = 10 // <--- this will only mutate `document` but not
`copy`
You use `class` property inside `struct`, so the `struct` is no longer
copyable. You have to do it yourself.
Zhaoxin
On Fri, Nov 18, 2016 at 10:09 PM, Adrian Zubarev <
adrian.zubarev at devandartist.com> wrote:
> Ups sorry for CCing the post to the evolution list. That happens from time
> to time. :/
>
>
>
> --
> Adrian Zubarev
> Sent with Airmail
>
> Am 18. November 2016 um 15:07:43, Adrian Zubarev (
> adrian.zubarev at devandartist.com) schrieb:
>
> I apologize about the weak/unowned issue I mentioned. I kinda missed that
> portion from the docs Weak references do not affect the result of this
> function..
>
> Okay it’s clear to me now why the result is evaluated as false.
>
> But how do I solve the COW problem for mutable views?
>
>
> --
> Adrian Zubarev
> Sent with Airmail
>
> Am 18. November 2016 um 15:04:55, Adrian Zubarev (
> adrian.zubarev at devandartist.com) schrieb:
>
> 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/26988292/attachment.html>
More information about the swift-users
mailing list