<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Nov 18, 2016, at 3:10 PM, Karl &lt;<a href="mailto:razielim@gmail.com" class="">razielim@gmail.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On 18 Nov 2016, at 20:18, John McCall &lt;<a href="mailto:rjmccall@apple.com" class="">rjmccall@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class=""><br class="Apple-interchange-newline">On Nov 18, 2016, at 7:40 AM, Karl &lt;<a href="mailto:razielim@gmail.com" class="">razielim@gmail.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><br class=""><div class=""><blockquote type="cite" class=""><div class="">On 18 Nov 2016, at 13:05, Adrian Zubarev via swift-users &lt;<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="bloop_markdown" style="font-family: Helvetica, Arial; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254);"><p class="" style="margin: 15px 0px; -webkit-margin-before: 0px;">Hi there,</p><p class="" style="margin: 15px 0px;">I just can’t get my head around mutable views and COW.</p><p class="" style="margin: 15px 0px;">Here is a small example:</p><pre class="" style="margin: 15px 0px; font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(204, 204, 204); overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;"><code class="swift" style="font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 0px; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;">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) -&gt; Int {
         
        return self._storageReference.keys.index(after: i)
    }
     
    public subscript(position: Int) -&gt; Int {
         
        get { return _storageReference.values[position] }
         
        set { self._storageReference.values[position] = newValue } // That will break COW
    }
}
</code></pre><p class="" style="margin: 15px 0px;">First of all the<span class="Apple-converted-space">&nbsp;</span><code class="" style="font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(234, 234, 234); margin: 0px 2px; padding: 0px 5px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;">_storageReference</code><span class="Apple-converted-space">&nbsp;</span>property is<span class="Apple-converted-space">&nbsp;</span><code class="" style="font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(234, 234, 234); margin: 0px 2px; padding: 0px 5px; word-break: normal; word-wrap: normal;">unowned</code><span class="Apple-converted-space">&nbsp;</span>because I wanted to check the following:</p><pre class="" style="margin: 15px 0px; font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(204, 204, 204); overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;"><code class="swift" style="font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 0px; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;">var document = Document()

print(CFGetRetainCount(document._storageReference)) //=&gt; 2
print(isKnownUniquelyReferenced(&amp;document._storageReference)) // true

var values = document.values

print(CFGetRetainCount(values._storageReference)) //=&gt; 2
print(isKnownUniquelyReferenced(&amp;values._storageReference)) // false
</code></pre><p class="" style="margin: 15px 0px;">Why is the second check false, even if the property is marked as<span class="Apple-converted-space">&nbsp;</span><code class="" style="font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(234, 234, 234); margin: 0px 2px; padding: 0px 5px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;">unowned</code><span class="Apple-converted-space">&nbsp;</span>for the view?</p><p class="" style="margin: 15px 0px;">Next up, I don’t have an idea how to correctly COW optimize this view. Assume the following scenario:</p><p class="" style="margin: 15px 0px;">Scenario A:</p><pre class="" style="margin: 15px 0px; font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(204, 204, 204); overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;"><code class="swift" style="font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 0px; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;">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  
</code></pre><p class="" style="margin: 15px 0px;">VS:</p><p class="" style="margin: 15px 0px;">Scenario B:</p><pre class="" style="margin: 15px 0px; font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(204, 204, 204); overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;"><code class="swift" style="font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 0px; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;">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 // &lt;--- this should only mutate `document` but not `copy`
</code></pre><p class="" style="margin: 15px 0px;">We could change the subscript setter on the mutable view like this:</p><pre class="" style="margin: 15px 0px; font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(204, 204, 204); overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;"><code class="swift" style="font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 0px; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;">set {
             
    if !isKnownUniquelyReferenced(&amp;self._storageReference) {
                 
        self._storageReference = ... // clone
    }
    self._storageReference.values[position] = newValue
}
</code></pre><p class="" style="margin: 15px 0px;">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<span class="Apple-converted-space">&nbsp;</span><code class="" style="font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(234, 234, 234); margin: 0px 2px; padding: 0px 5px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;">unowned</code><span class="Apple-converted-space">&nbsp;</span>the function<span class="Apple-converted-space">&nbsp;</span><code class="" style="font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(234, 234, 234); margin: 0px 2px; padding: 0px 5px; word-break: normal; word-wrap: normal;">isKnownUniquelyReferenced</code><span class="Apple-converted-space">&nbsp;</span>will return false for scenario A.</p><p class="" style="margin: 15px 0px;">Any suggestions?<span class="Apple-converted-space">&nbsp;</span></p><p class="" style="margin: 15px 0px;">PS: In general I also wouldn’t want to use<span class="Apple-converted-space">&nbsp;</span><code class="" style="font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(234, 234, 234); margin: 0px 2px; padding: 0px 5px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;">unowned</code><span class="Apple-converted-space">&nbsp;</span>because the view should be able to outlive it’s parent.</p><div class="" style="margin: 15px 0px;"><br class="webkit-block-placeholder"></div></div><div class="bloop_original_html" style="font-family: Helvetica, Arial; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254);"><div id="bloop_customfont" class="" style="font-family: Helvetica, Arial; font-size: 13px; margin: 0px;"><br class=""></div><br class=""><div id="bloop_sign_1479469826202990080" class="bloop_sign"><div class="" style="font-family: helvetica, arial; font-size: 13px;">--&nbsp;<br class="">Adrian Zubarev<br class="">Sent with Airmail</div></div></div><div class="bloop_markdown" style="font-family: Helvetica, Arial; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254);"><div class="" style="margin: 15px 0px; -webkit-margin-before: 0px;"><br class="webkit-block-placeholder"></div></div><span class="" style="font-family: Helvetica, Arial; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254); float: none; display: inline !important;">_______________________________________________</span><br class="" style="font-family: Helvetica, Arial; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254);"><span class="" style="font-family: Helvetica, Arial; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254); float: none; display: inline !important;">swift-users mailing list</span><br class="" style="font-family: Helvetica, Arial; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254);"><a href="mailto:swift-users@swift.org" class="" style="color: rgb(65, 131, 196); background-color: rgb(254, 254, 254); text-decoration: none; font-family: Helvetica, Arial; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">swift-users@swift.org</a><br class="" style="font-family: Helvetica, Arial; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254);"><a href="https://lists.swift.org/mailman/listinfo/swift-users" class="" style="color: rgb(65, 131, 196); background-color: rgb(254, 254, 254); text-decoration: none; font-family: Helvetica, Arial; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">https://lists.swift.org/mailman/listinfo/swift-users</a><br class="" style="font-family: Helvetica, Arial; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254);"></div></blockquote></div><br class=""><div class=""><br class=""></div><div class="">This is kind of an invalid/unsafe design IMO; DocumentValues may escape the scope of the Document and the underlying storage may be deallocated.</div><div class=""><br class=""></div><div class="">Instead, I’d recommend a function:</div><div class=""><br class=""></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class=""><font face="Courier" class="">func withDocumentValues&lt;T&gt;(_ invoke: (inout DocumentValues)-&gt;T) -&gt; T {</font></div><div class=""><font face="Courier" class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>var view = DocumentValues(self)</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; &nbsp; &nbsp; defer { _fixLifetime(view) }</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; &nbsp; &nbsp; return invoke(&amp;view)</font></div><div class=""><font face="Courier" class="">}</font></div><div class=""><font face="Courier" class=""><br class=""></font></div></blockquote>(unfortunately, this isn’t completely safe because somebody could still copy the<span class="Apple-converted-space">&nbsp;</span><font face="Courier" class="">DocumentValues</font><span class="Apple-converted-space">&nbsp;</span>from their closure, the same way you can copy the pointer from String’s<span class="Apple-converted-space">&nbsp;</span><font face="Courier" class="">withCString</font>, but that’s a limitation of Swift right now)</div></div></blockquote><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><br class=""></div><div class="">CC: John McCall, because I read his suggestion in the thread about contiguous memory/borrowing that we could have a generalised<span class="Apple-converted-space">&nbsp;</span><font face="Courier" class="">@noescape</font>. In this example, you would want the<span class="Apple-converted-space">&nbsp;</span><font face="Courier" class="">DocumentValues</font><span class="Apple-converted-space">&nbsp;</span>parameter in the closure to be<font face="Courier" class=""><span class="Apple-converted-space">&nbsp;</span>@noescape</font>.</div></div></div></blockquote><div class=""><br class=""></div><div class="">I think you guys understand this stuff, but let me talk through it, and I hope it will be illuminating about where we're thinking of taking the language.</div><div class=""><br class=""></div>In value semantics, you expect something like:</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">&nbsp; let values = document.values</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">to produce an independent value, and mutations of it shouldn't affect the original document value.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">But there<span class="Apple-converted-space">&nbsp;</span><i class="">is</i><span class="Apple-converted-space">&nbsp;</span>a situation where values aren't independent, which is when one value is just a projected component of another. &nbsp;In Swift, this is (currently, at least) always expressed with properties and subscripts. So when you write:</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">&nbsp; document.values.mutateInSomeWay()</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">this is expected to actually change the document. &nbsp;So it makes language sense for views like "values" to be expressed in this way; the only question is whether that can be done efficiently while still providing a satisfactory level of safety etc.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">When a property is actually stored directly in a value, Swift allows direct access to it (although for subscripts this mechanism is not currently documented + exposed, intentionally). &nbsp;This sort of direct access is optimal, but it's not general enough for use cases like views and slices because the slice value doesn't actually exist anywhere; it needs to be created. &nbsp;We do allow properties to be defined with get / set, but there are problems with that, which are exactly what you're seeing: slice values need to assert ownership of the underlying data if they're going to be used as independent values, but they also need to not assert ownership so that they don't interfere with copy-on-write. &nbsp;get / set isn't good enough for this because get is used to both derive an independent value (which should assert ownership) and initiate a mutation (which should not). &nbsp;The obvious solution is to allow a third accessor to be provided which is used when a value is mutated, as opposed to just copied (get) or overwritten whole-sale (set). &nbsp;We're still working out various ideas for how this will look at the language level.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">So that would be sufficient to allow DocumentValues to store either a stong or an unowned reference to the storage, depending on how the property is being used. &nbsp;However, that creates the problem that, like with Karl's solution, the value can be copied during the mutation, and the user would expect that to create an independent value, i.e. to promote an unowned reference to strong. &nbsp;The most general solution for this is to provide some sort of "copy constructor" feature which would be used to create an independent value. &nbsp;But that's a pretty large hammer to pull out for this nail.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">A third problem is that the original document can be copied and/or mutated during the projection of the DocumentValues, leaving the copy / the view in a potentially inconsistent state. &nbsp;But this is a problem that we expect to thoroughly solve with the ownership system, which will statically (or dynamically when necessary) prevent simultaneous conflicting accesses to a value.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">In the meantime, I think the best alternative is to</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">&nbsp; - allow the view to hold either an unowned or owned reference and</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">&nbsp; - create a callback-based accessor like Karl's and document that copies from the value are not permitted</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">On a purely technical level:</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><blockquote type="cite" class=""><div class=""><div class="bloop_markdown" style="font-family: Helvetica, Arial; font-size: 13px; background-color: rgb(254, 254, 254);"><pre class="" style="margin-top: 15px; margin-bottom: 15px; font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(204, 204, 204); overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;"><code class="swift" style="font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; color: inherit; border: 0px; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;">print(isKnownUniquelyReferenced(&amp;values._storageReference)) // false
</code></pre><p class="" style="margin: 15px 0px;">Why is the second check false, even if the property is marked as&nbsp;<code class="" style="font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(234, 234, 234); margin: 0px 2px; padding: 0px 5px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;">unowned</code>&nbsp;for the view?</p></div></div></blockquote></div></div></blockquote></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">A function taking an "inout T" expects to be passed an l-value for an ordinary (strong) reference. &nbsp;Swift makes this work when passing an unowned or weak reference by passing a temporary variable holding a temporarily-promoted strong reference. &nbsp;That's usually good, but it's wrong for isKnownUniquelyReferenced, and even more unfortunately, I don't think there's any supported way to make this work in the current compiler; you need language support.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">John.</div></div></blockquote></div><br class=""><div class=""><br class=""></div><div class="">That’s very illuminating.&nbsp;</div><div class=""><br class=""></div><div class="">For pure ‘views’, I would actually approach it in a different way (and I wrote a bit about this a while back on the lists): those additional views should not be separate, concrete types with pointers back to the data; they should be protocols on a single type which owns the data. This would simplify situations like String’s various lazily-encoding UTF(8/16/32) views and make it easier to write generic code.</div></div></div></blockquote><div><br class=""></div>Leaving all else aside, this would help only for unparameterized views. &nbsp;The core team needs to solve slices, which are dynamically parameterized by the extents of the slice, and so will need to solve this more generally. &nbsp;I suspect that that more general solution will also be a more satisfactory solution to the less general problem of unparameterized slices.</div><div><br class=""></div><div>John.</div><div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><br class=""></div><div class=""><div class="">In C, we had one big global namespace. With C++, types could contain function members and became their own namespaces. I believe protocols in Swift should be separate namespaces below their types, and you should have unlimited freedom to name protocol members how you like, as well as conform to multiple overlapping protocols. For example, in my dreams String would be implemented something like this (just UTF8/16, for brevity):</div></div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Courier" class="">protocol UTF8Sequence : Sequence&nbsp;</font><span style="font-family: Courier;" class="">where Element = UTF8CodePoint&nbsp;</span><span style="font-family: Courier;" class="">{}</span></div><div class=""><font face="Courier" class="">protocol UTF16Sequence : Sequence&nbsp;</font><span style="font-family: Courier;" class="">where</span><font face="Courier" class="">&nbsp;Element = UTF16CodePoint {}</font></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><font face="Courier" class="">struct String { /* ... */ }</font></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><font face="Courier" class="">extension String : UTF8Sequence {</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; struct Iterator { /* UTF8-encoding iterator */ }</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; func makeIterator() -&gt; Iterator { return Iterator(_core) }</font></div><div class=""><font face="Courier" class="">}</font></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><div class=""><font face="Courier" class="">extension String : UTF16Sequence {</font></div></div><div class=""><div class=""><font face="Courier" class="">&nbsp; &nbsp; struct Iterator { /* UTF16-encoding iterator */ }</font></div></div><div class=""><div class=""><font face="Courier" class="">&nbsp; &nbsp; func makeIterator() -&gt; Iterator { return Iterator(_core) }</font></div></div><div class=""><div class=""><font face="Courier" class="">}</font></div></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><font face="Courier" class="">type(of: “hello”.UTF8Sequence.makeIterator()) &nbsp;// String.UTF8Sequence.Iterator</font></div><div class=""><span style="font-family: Courier;" class="">type(of: “hello”.UTF16Sequence.makeIterator()) // String.UTF16Sequence.Iterator</span></div></blockquote><div class=""><br class=""></div><div class="">The members which are bound to protocols would have that protocol mangled in to its name; so we’d have:&nbsp;<font face="Courier" class="">String.UTF8Sequence.makeIterator() -&gt; String.UTF8Sequence.Iterator</font>.</div><div class="">This is only possible because each conformance to UTF8Sequence lives in a parallel universe with its own version of Sequence and any other inherited protocols; String.UTF8Sequence actually is the protocol witness table itself, and we are explicitly building up all of its requirements in its own little bubble. This allows us to do some pretty neat things, like represent the fact that every UTF8Sequence is also viewable as a sequence of characters:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Courier" class="">protocol CharacterSequence : Sequence where Element = Character {}</font></div><div class=""><font face="Courier" class=""><br class=""></font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Courier" class="">protocol UTF8Sequence : CharacterSequence, Sequence where Element = UTF8CodePoint {}</font></div><div class=""><font face="Courier" class="">extension UTF8Sequence { /* default implementation of CharacterSequence, which turns UTF8 codepoints -&gt; Characters */&nbsp;</font><span style="font-family: Courier;" class="">}</span></div></blockquote><div class=""><br class=""></div><div class="">String, however, would implement CharacterSequence natively. So String’s <font face="Courier" class="">UTF8Sequence.CharacterSequence</font> witness table could redirect to those more efficient implementations, which don't encode to UTF8 as a middle-man:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Courier" class="">extension String : UTF8Sequence {</font></div></div><div class=""><font face="Courier" class=""><br class=""></font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Courier" class="">// We need to implement:</font></div><div class=""><font face="Courier" class="">// - Sequence (where Iterator.Element is a UTF8CodePoint) - required</font></div><div class=""><font face="Courier" class="">// - Sequence (where Iterator.Element is a Character) &nbsp; &nbsp; — optionally, since there is a default</font></div></blockquote></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Courier" class=""><br class=""></font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Courier" class="">struct Iterator { /* UTF8-encoding iterator */ }</font></div></div></blockquote></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Courier" class="">func makeIterator() -&gt; Iterator { return Iterator(_core) }</font></div></div></blockquote></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Courier" class=""><br class=""></font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Courier" class="">// The type-checker could probably figure out which Iterator we mean here, but in cases where it can’t,</font></div><div class=""><font face="Courier" class="">// we disambiguate by explicitly saying which conformance it belongs to.</font></div><div class=""><br class=""></div></blockquote></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><font face="Courier" class="">typealias CharacterSequence.Iterator = String.CharacterSequence.Iterator</font></blockquote></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Courier" class="">func CharacterSequence.makeIterator() -&gt; String.CharacterSequence.Iterator { return self.CharacterSequence.makeIterator() }</font></div></blockquote></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Courier" class="">}</font></div></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><font face="Courier" class="">func chant(_ thingToChant: CharacterSequence) {</font></div><div class=""><font face="Courier" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>for character in thingToChant {</font></div><div class=""><font face="Courier" class=""><span class="Apple-tab-span" style="white-space:pre">                </span>print(“Give me a \(character)!”)</font></div><div class=""><font face="Courier" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</font></div><div class=""><font face="Courier" class="">}</font></div><div class=""><br class=""></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Courier" class="">chant(“hello") &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// String is a CharacterSequence, so String.CharacterSequence exists</font></div><div class=""><font face="Courier" class="">chant(myCustomUTF8Sequence) // A UTF8Sequence is a CharacterSequence, so MyCustomUTF8Sequence.CharacterSequence exists (maybe pointing to the default witnesses, maybe not)</font></div><div class=""><br class=""></div></blockquote><div class=""><br class=""></div><div class="">The unfortunate thing about this is that it can be a bit verbose at the usage-site. For the common case (i.e. everything today) where protocols don’t overlap, the compiler could easily disambiguate:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Courier" class="">protocol A { func doSomething() }</font></div><div class=""><font face="Courier" class="">extension A { func doSomethingElse() }</font></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><font face="Courier" class="">struct MyStruct : A {</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; func doSomething() { … }</font></div><div class=""><font face="Courier" class="">}</font></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><font face="Courier" class="">let aThing = MyStruct()</font></div><div class=""><font face="Courier" class="">aThing.doSomething() &nbsp; &nbsp; // Compiler expands this to&nbsp;‘aThing.A.doSomething()’</font></div><div class=""><font face="Courier" class="">aThing.doSomethingElse()&nbsp;</font><span style="font-family: Courier;" class="">// Compiler expands this to&nbsp;‘aThing.A.doSomethingElse()’</span></div></blockquote><div class=""><br class=""></div><div class="">Since String could conform to CharacterSequence in multiple ways (natively, or via any of the UTF8/16 sequences), any algorithms we write in protocol extensions would not be unambiguous. I’m not sure how to solve that one.</div><div class=""><br class=""></div><div class="">- Karl</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div></div></div></blockquote></div><br class=""></body></html>