<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div><br><br><div>Sent from my moss-covered three-handled family gradunza</div></div><div><br>On Feb 11, 2017, at 5:16 AM, Karl Wagner &lt;<a href="mailto:razielim@gmail.com">razielim@gmail.com</a>&gt; wrote:<br><br></div><blockquote type="cite"><div><span></span><br><blockquote type="cite"><span>On 11 Feb 2017, at 04:23, Brent Royal-Gordon &lt;<a href="mailto:brent@architechies.com">brent@architechies.com</a>&gt; wrote:</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><blockquote type="cite"><span>On Feb 10, 2017, at 5:49 PM, Jonathan Hull via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>&gt; wrote:</span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span></span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span>An easier to implement, but slightly less useful approach, would be to have methods which take an array of indexes along with the proposed change, and then it adjusts the indexes (or replaces them with nil if they are invalid) as it makes the update. &nbsp;For example:</span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span></span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span> &nbsp; &nbsp;func append(_ element:Element, adjusting: [Index]) -&gt; [Index?]</span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span> &nbsp; &nbsp;func appending(_ element:Element, adjusting: [Index]) -&gt; (Self, [Index?])</span><br></blockquote></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>This is a very interesting idea. A couple observations:</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>1. The problem of adjusting indices is not just a String one. It also applies to Array, among other things.</span></blockquote></div></blockquote><div><br></div>You can think of this as a generalization of AttributedString<br><blockquote type="cite"><div><blockquote type="cite"><span>2. This logic could be encapsulated and reused in a separate type. For instance, imagine:</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span> &nbsp; &nbsp;let myStringProxy = IndexTracking(collection: myString, trackedIndices: [someIndex, otherIndex])</span><br></blockquote><blockquote type="cite"><span> &nbsp; &nbsp;myStringProxy.insert("foo", at: otherIndex)</span><br></blockquote><blockquote type="cite"><span> &nbsp; &nbsp;(someIndex, otherIndex) = (stringProxy.trackedIndices[0], stringProxy.trackedIndices[1])</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>Or, with a helper method:</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span> &nbsp; &nbsp;myString.withTracked(&amp;someIndex) { myStringProxy in</span><br></blockquote><blockquote type="cite"><span> &nbsp; &nbsp; &nbsp; &nbsp;myStringProxy.insert("foo", at: otherIndex)</span><br></blockquote><blockquote type="cite"><span> &nbsp; &nbsp;}</span></blockquote></div></blockquote><div><br></div>You can't adjust indices in arbitrary&nbsp;<span style="background-color: rgba(255, 255, 255, 0);">RangeReplaceableCollections</span>&nbsp;without penalizing the performance of <i>all</i>&nbsp;RangeReplaceableCollections. Also, to do it without introducing reference semantics you need to bundle the index storage with the collection or explicitly make the collection of indices to be updated avAilable input to the range replacement methods. Given the latter, you could build something like this to implement the former:<div><br></div><div>struct IndexTracked&lt;C: RangeReplaceableCollection&gt;&nbsp;</div><div><br></div><div>Also, you probably want his thing to adjust <u>ranges</u> rather than indices because otherwise you need to decide whether to adjust an index when there is an insertion at that position. &nbsp; Does it stick to the left or right element?</div><div><br><blockquote type="cite"><div><blockquote type="cite"><span>3. An obstacle to doing this correctly is that a collection's index invalidation behavior is not expressed in the type system. </span></blockquote></div></blockquote><div><br></div>I don't see why that's an issue.&nbsp;</div><div><br><blockquote type="cite"><div><blockquote type="cite"><span>If there were a protocol like:</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span> &nbsp; &nbsp;protocol RangeReplaceableWithEarlierIndexesStableCollection: RangeReplaceableCollection {}</span><br></blockquote></div></blockquote><div><br></div>There's one interesting wrinkle on invalidation I discovered recently: there is an important class of indices that are not invalidated <u>as positions</u> when they precede the change, but may be invalidated for <u>movement:</u> those that store some cached information about following elements, such as transcoded Unicode code units.&nbsp;</div><div><br><blockquote type="cite"><div><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>That would help us here.</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>-- </span><br></blockquote><blockquote type="cite"><span>Brent Royal-Gordon</span><br></blockquote><blockquote type="cite"><span>Architechies</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><span></span><br><span></span><br><span>I mentioned this much earlier in the thread. My preferred solution would be some kind of RRC-like protocol where mutating methods returned an associated “IndexDisplacement” type. That IndexDisplacement would store, for each operation, the offset and number of index-positions which have been inserted/removed, and know how to translate an index in the previous state in to one in the new state.</span><br><span></span><br><span>You would still need to manually adjust your stored indexes using that IndexDisplacement, but it’d be less error-prone as the logic is written for you.</span><br><span></span><br><span>The standard (non-IndexDisplacement-returning) RRC methods could then be implemented as wrappers which discard the displacement.</span><br><span></span><br><span>- Karl</span></div></blockquote></div></body></html>