<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="">Hi swift-evolution 😊<div class=""><br class=""></div><div class="">String’s Views have a few odd properties that have bothered me for a while. I initially did not bring it up because I thought a String redesign was coming. But since Swift 3 will be released very soon—and with the recent focus on breaking changes—I thought now might be a good time to talk about it. </div><div class=""><br class=""></div><div class="">## Subsequences of UTF16View and CharacterView don’t use the same indices as the original collection</div><div class=""><br class=""></div><div class="">One requirement of the Collection protocol is </div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 12px; line-height: normal; color: rgb(39, 39, 39);" class=""><div style="margin: 0px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #d24bbe" class="">public</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #d24bbe" class="">subscript</span><span style="font-variant-ligatures: no-common-ligatures" class="">(bounds: </span><span style="font-variant-ligatures: no-common-ligatures; color: #a233e6" class="">Range</span><span style="font-variant-ligatures: no-common-ligatures" class=""><</span><span style="font-variant-ligatures: no-common-ligatures; color: #a233e6" class="">Self</span><span style="font-variant-ligatures: no-common-ligatures" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #7b33cd" class="">Index</span><span style="font-variant-ligatures: no-common-ligatures" class="">>) -> </span><span style="font-variant-ligatures: no-common-ligatures; color: #a233e6" class="">Self</span><span style="font-variant-ligatures: no-common-ligatures" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #7b33cd" class="">SubSequence</span><span style="font-variant-ligatures: no-common-ligatures" class=""> { </span><span style="font-variant-ligatures: no-common-ligatures; color: #d24bbe" class="">get</span><span style="font-variant-ligatures: no-common-ligatures" class=""> }</span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div></div></div><div class="">whose documentation says:</div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><div style="margin: 0px; font-size: 12px; line-height: normal; color: rgb(0, 132, 0);" class=""><div style="margin: 0px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">/// Accesses a contiguous subrange of the collection's elements.</span></div><div style="margin: 0px; line-height: normal; font-family: Menlo; color: rgb(39, 39, 39);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #008400" class="">///</span></div><div style="margin: 0px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">/// The accessed slice uses the same indices for the same elements as the</span></div><div style="margin: 0px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">/// original collection uses.</span></div></div></div><div class=""><br class=""></div><div class="">However, it appears that UTF16View and CharacterView don’t follow the documentation. For example:</div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><div style="margin: 0px; font-size: 12px; line-height: normal; color: rgb(251, 37, 28);" class=""><div style="margin: 0px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #d24bbe" class="">let</span><span style="font-variant-ligatures: no-common-ligatures; color: #272727" class=""> str = </span><span style="font-variant-ligatures: no-common-ligatures" class="">"Hello World!"</span><span style="font-variant-ligatures: no-common-ligatures; color: #272727" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">utf16</span></div><div style="margin: 0px; line-height: normal; color: rgb(39, 39, 39);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #d24bbe" class="">let</span><span style="font-variant-ligatures: no-common-ligatures" class=""> (start, end) = (</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">str</span><span style="font-variant-ligatures: no-common-ligatures" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #7d1e7b" class="">index</span><span style="font-variant-ligatures: no-common-ligatures" class="">(</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">str</span><span style="font-variant-ligatures: no-common-ligatures" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">startIndex</span><span style="font-variant-ligatures: no-common-ligatures" class="">, offsetBy: </span><span style="font-variant-ligatures: no-common-ligatures; color: #272ad8" class="">2</span><span style="font-variant-ligatures: no-common-ligatures" class="">), </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">str</span><span style="font-variant-ligatures: no-common-ligatures" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #7d1e7b" class="">index</span><span style="font-variant-ligatures: no-common-ligatures" class="">(</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">str</span><span style="font-variant-ligatures: no-common-ligatures" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">startIndex</span><span style="font-variant-ligatures: no-common-ligatures" class="">, offsetBy: </span><span style="font-variant-ligatures: no-common-ligatures; color: #272ad8" class="">9</span><span style="font-variant-ligatures: no-common-ligatures" class="">))</span></div><div style="margin: 0px; line-height: normal; color: rgb(39, 39, 39); min-height: 14px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; line-height: normal; color: rgb(39, 39, 39);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #d24bbe" class="">let</span><span style="font-variant-ligatures: no-common-ligatures" class=""> sub1 = </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">str</span><span style="font-variant-ligatures: no-common-ligatures" class="">[</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">start</span><span style="font-variant-ligatures: no-common-ligatures" class=""> ..< </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">end</span><span style="font-variant-ligatures: no-common-ligatures" class="">]</span></div><div style="margin: 0px; line-height: normal; color: rgb(0, 132, 0);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #7d1e7b" class="">print</span><span style="font-variant-ligatures: no-common-ligatures; color: #272727" class="">(</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">sub1</span><span style="font-variant-ligatures: no-common-ligatures; color: #272727" class="">) </span><span style="font-variant-ligatures: no-common-ligatures" class="">// llo Wor</span></div><div style="margin: 0px; line-height: normal; color: rgb(39, 39, 39); min-height: 14px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; line-height: normal; color: rgb(112, 61, 170);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #d24bbe" class="">let</span><span style="font-variant-ligatures: no-common-ligatures; color: #272727" class=""> sub2 = </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">str</span><span style="font-variant-ligatures: no-common-ligatures; color: #272727" class="">[</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">sub1</span><span style="font-variant-ligatures: no-common-ligatures; color: #272727" class="">.</span><span style="font-variant-ligatures: no-common-ligatures" class="">startIndex</span><span style="font-variant-ligatures: no-common-ligatures; color: #272727" class=""> ..< </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">sub1</span><span style="font-variant-ligatures: no-common-ligatures; color: #272727" class="">.</span><span style="font-variant-ligatures: no-common-ligatures" class="">endIndex</span><span style="font-variant-ligatures: no-common-ligatures; color: #272727" class="">]</span></div><div style="margin: 0px; line-height: normal; color: rgb(0, 132, 0);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #7d1e7b" class="">print</span><span style="font-variant-ligatures: no-common-ligatures; color: #272727" class="">(</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">sub2</span><span style="font-variant-ligatures: no-common-ligatures; color: #272727" class="">) </span><span style="font-variant-ligatures: no-common-ligatures" class="">// Hello W</span></div></div></div></div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class="">Here, using `sub1`’s indices on the original collection `str` returns a completely different subsequence.</div><div style="margin: 0px; line-height: normal;" class="">I think that, ideally, `sub2` should be equal to `sub1`, just like when using UTF8View and UnicodeScalarView.</div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class="">## Accessing elements past the end of the subsequence</div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class="">Consider this piece of code:</div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class=""><div style="margin: 0px; font-size: 12px; line-height: normal; font-family: Menlo; color: rgb(251, 37, 28);" class=""><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #d24bbe" class="">let</span><span style="font-variant-ligatures: no-common-ligatures; color: #272727" class=""> str = </span><span style="font-variant-ligatures: no-common-ligatures" class="">"Hello World!"</span><span style="font-variant-ligatures: no-common-ligatures; color: #272727" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">utf8</span></div></div><div style="margin: 0px; font-size: 12px; line-height: normal; font-family: Menlo; color: rgb(251, 37, 28);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: rgb(210, 75, 190);" class="">let</span><span style="color: rgb(39, 39, 39); font-variant-ligatures: no-common-ligatures;" class=""> (start, end) = (</span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(79, 129, 135);" class="">str</span><span style="color: rgb(39, 39, 39); font-variant-ligatures: no-common-ligatures;" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(125, 30, 123);" class="">index</span><span style="color: rgb(39, 39, 39); font-variant-ligatures: no-common-ligatures;" class="">(</span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(79, 129, 135);" class="">str</span><span style="color: rgb(39, 39, 39); font-variant-ligatures: no-common-ligatures;" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);" class="">startIndex</span><span style="color: rgb(39, 39, 39); font-variant-ligatures: no-common-ligatures;" class="">, offsetBy: </span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(39, 42, 216);" class="">2</span><span style="color: rgb(39, 39, 39); font-variant-ligatures: no-common-ligatures;" class="">), </span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(79, 129, 135);" class="">str</span><span style="color: rgb(39, 39, 39); font-variant-ligatures: no-common-ligatures;" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(125, 30, 123);" class="">index</span><span style="color: rgb(39, 39, 39); font-variant-ligatures: no-common-ligatures;" class="">(</span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(79, 129, 135);" class="">str</span><span style="color: rgb(39, 39, 39); font-variant-ligatures: no-common-ligatures;" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);" class="">startIndex</span><span style="color: rgb(39, 39, 39); font-variant-ligatures: no-common-ligatures;" class="">, offsetBy: </span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(39, 42, 216);" class="">9</span><span style="color: rgb(39, 39, 39); font-variant-ligatures: no-common-ligatures;" class="">))</span></div><div style="margin: 0px; font-size: 12px; line-height: normal; font-family: Menlo; color: rgb(39, 39, 39); min-height: 14px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 12px; line-height: normal; font-family: Menlo; color: rgb(39, 39, 39);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #d24bbe" class="">let</span><span style="font-variant-ligatures: no-common-ligatures" class=""> sub1 = </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">str</span><span style="font-variant-ligatures: no-common-ligatures" class="">[</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">start</span><span style="font-variant-ligatures: no-common-ligatures" class=""> ..< </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">end</span><span style="font-variant-ligatures: no-common-ligatures" class="">]</span></div><div style="margin: 0px; font-size: 12px; line-height: normal; font-family: Menlo; color: rgb(0, 132, 0);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #7d1e7b" class="">print</span><span style="font-variant-ligatures: no-common-ligatures; color: #272727" class="">(</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">sub1</span><span style="font-variant-ligatures: no-common-ligatures; color: #272727" class="">) </span><span style="font-variant-ligatures: no-common-ligatures" class="">// llo Wor</span></div><div style="margin: 0px; font-size: 12px; line-height: normal; font-family: Menlo; color: rgb(39, 39, 39); min-height: 14px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 12px; line-height: normal; font-family: Menlo; color: rgb(39, 39, 39);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #d24bbe" class="">let</span><span style="font-variant-ligatures: no-common-ligatures" class=""> pastEnd = </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">sub1</span><span style="font-variant-ligatures: no-common-ligatures" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #7d1e7b" class="">index</span><span style="font-variant-ligatures: no-common-ligatures" class="">(</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">sub1</span><span style="font-variant-ligatures: no-common-ligatures" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">endIndex</span><span style="font-variant-ligatures: no-common-ligatures" class="">, offsetBy: </span><span style="font-variant-ligatures: no-common-ligatures; color: #272ad8" class="">2</span><span style="font-variant-ligatures: no-common-ligatures" class="">)</span></div><div style="margin: 0px; font-size: 12px; line-height: normal; font-family: Menlo; color: rgb(39, 39, 39); min-height: 14px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 12px; line-height: normal; font-family: Menlo; color: rgb(39, 39, 39);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #d24bbe" class="">let</span><span style="font-variant-ligatures: no-common-ligatures" class=""> sub2 = </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">sub1</span><span style="font-variant-ligatures: no-common-ligatures" class="">[</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">sub1</span><span style="font-variant-ligatures: no-common-ligatures" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">startIndex</span><span style="font-variant-ligatures: no-common-ligatures" class=""> ..< </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">pastEnd</span><span style="font-variant-ligatures: no-common-ligatures" class="">]</span></div><div style="margin: 0px; font-size: 12px; line-height: normal; font-family: Menlo; color: rgb(0, 132, 0);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #7d1e7b" class="">print</span><span style="font-variant-ligatures: no-common-ligatures; color: #272727" class="">(</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">sub2</span><span style="font-variant-ligatures: no-common-ligatures; color: #272727" class="">) </span><span style="font-variant-ligatures: no-common-ligatures" class="">// llo World</span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div></div><div style="margin: 0px; line-height: normal;" class="">I was able to access elements of the original string that should be beyond the reach of `sub1`.</div><div style="margin: 0px; line-height: normal;" class="">Using a UnicodeScalarView gives an odd result too: indices past the end are seemingly ignored, and `sub2` is equal to `sub1`.</div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class="">## Conclusion</div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class="">I think String’s Views should</div><div style="margin: 0px; line-height: normal;" class="">1. Follow Collection’s documentation by using the same indices for their subsequences</div><div style="margin: 0px; line-height: normal;" class="">2. Provide safe, consistent behavior when using a subscript operation with a past-the-end index </div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class="">However, this means more breaking changes that won’t be easy to detect.</div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class="">Thoughts?</div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class="">Loïc</div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div></body></html>