<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>mikeash.com pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html comments</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>mikeash.com Recent Comments</description><lastBuildDate>Sun, 10 May 2026 06:23:47 GMT</lastBuildDate><generator>PyRSS2Gen-1.0.0</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Rennie - 2016-12-14 08:03:50</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>"(Incidentally, I think that representing all these different concepts as a single string type is a mistake. Human-readable text, file paths, SQL statements, and others are all conceptually different, and this should be represented as different types at the language level. I think that having different conceptual kinds of strings be distinct types would eliminate a lot of bugs. I'm not aware of any language or standard library that does this, though.)" 
&lt;br /&gt;
&lt;br /&gt;Boy, do I disagree. I have painful memories of working with some C++ programs where there were about a half-dozen different representations for string. The basic 8-bit zero-terminated strings, a variation that had a 16-bit length in front, two different "wide character" types from two different development groups in Microsoft and two other text string "standards" created by independent organisations or library implementers. What a mess. Every time some text data had to be conveyed from one part of the program to another, or calling a function at a different level in the implementation, it almost always involved converting from one kind of string representation to another.
&lt;br /&gt;
&lt;br /&gt;Please, never again!</description><guid isPermaLink="true">7af9d6a15286309b71bd9d7bb777b902</guid><pubDate>Wed, 14 Dec 2016 08:03:50 GMT</pubDate></item><item><title>الوليد - 2016-09-30 15:55:46</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>Do make sure you have optimizations enabled when testing, though. Swift is still slower, but it speeds up by about a factor of 10. Also, it depends pretty heavily on the encoding and the data. UTF-16 is NSString's native encoding, so creating an NSString from a UTF-16 array is basically just a memcpy. Try with UTF-8 and a Unicode flag as the repeated Character and while Swift still loses the race, it "only" loses by a factor of 3-4 instead of a factor of a bazillion.</description><guid isPermaLink="true">282785680e7878d230ff9d3ddf062cc8</guid><pubDate>Fri, 30 Sep 2016 15:55:46 GMT</pubDate></item><item><title>Lisper - 2016-05-29 19:19:21</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>"(Incidentally, I think that representing all these different concepts as a single string type is a mistake. Human-readable text, file paths, SQL statements, and others are all conceptually different, and this should be represented as different types at the language level. I think that having different conceptual kinds of strings be distinct types would eliminate a lot of bugs. I'm not aware of any language or standard library that does this, though.)"
&lt;br /&gt;
&lt;br /&gt;Common Lisp essentially does this: #P"foo" denotes a pathname string, though many stdlib functions still also accept ordinary strings.
&lt;br /&gt;
&lt;br /&gt;Python also recently added Path objects, though there's no syntax for them, and I'm not sure anyone uses them yet.
&lt;br /&gt;
&lt;br /&gt;Database interfaces don't tend to be part of programming languages, but most database *libraries* do this.  Again, though, since most languages don't offer extensible syntax, they have to use function calls or classes, like SQLAlchemy's text() wrapper.
&lt;br /&gt;</description><guid isPermaLink="true">6a350793cba88917a4d8a2e8ae4b5cfe</guid><pubDate>Sun, 29 May 2016 19:19:21 GMT</pubDate></item><item><title>Aaron - 2016-01-11 21:06:19</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>I'm sorry, I just re-read your post and saw that you covered this. Please ignore my last comment.</description><guid isPermaLink="true">b7ac7dd2aa76e38ba0a57cf3d8a4a296</guid><pubDate>Mon, 11 Jan 2016 21:06:19 GMT</pubDate></item><item><title>Aaron - 2016-01-11 21:04:16</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>I wondered about your thoughts on why integer subscripts are not provided for the various string views? For example, it would be handy to be able to write:
&lt;br /&gt;
&lt;br /&gt;&lt;code&gt;let char = "Hello!".characters[0]&lt;/code&gt;
&lt;br /&gt;
&lt;br /&gt;It would be easy to implement:
&lt;br /&gt;
&lt;br /&gt;&lt;code&gt;subscript(index: Int) -&amp;gt; Character {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;let index = startIndex.advancedBy(index)
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return self[index]
&lt;br /&gt;}&lt;/code&gt;
&lt;br /&gt;
&lt;br /&gt;I really like the String API, but I think what trips people up more than anything is not having simple integer subscript access to the elements, and having instead to go through the process of creating an Index and advancing it.
&lt;br /&gt;
&lt;br /&gt;Given how easy it would be to implement, any ideas why it is not available? Is it a performance thing?</description><guid isPermaLink="true">a67f6d0bd3ff0fcaf8dcd1e4e9757aff</guid><pubDate>Mon, 11 Jan 2016 21:04:16 GMT</pubDate></item><item><title>Keegan - 2015-12-18 10:53:20</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>What if all you only need to deal with ascii? Is there a swift library that has less verbose string functionality?
&lt;br /&gt;
&lt;br /&gt;Now that swift is open sourced many people are going to want to use it for things don't require Unicode, and thus don't need the complexity of the built in string type.
&lt;br /&gt;</description><guid isPermaLink="true">741e9360dae048b00930b9e76e98c242</guid><pubDate>Fri, 18 Dec 2015 10:53:20 GMT</pubDate></item><item><title>Chad - 2015-11-10 03:00:21</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>As a unicode nerd, I'm really happy that someone with deep domain knowledge finally developed a string API that matches reality. I like that Swift takes inspiration from functional programming languages where the type system exists to enforce correct usage of the API, not just to say what the bytes will be in memory.
&lt;br /&gt;
&lt;br /&gt;On this aside:
&lt;br /&gt;
&lt;br /&gt;&lt;div class="blogcommentquote"&gt;&lt;div class="blogcommentquoteinner"&gt;(Incidentally, I think that representing all these different concepts as a single string type is a mistake. Human-readable text, file paths, SQL statements, and others are all conceptually different, and this should be represented as different types at the language level. I think that having different conceptual kinds of strings be distinct types would eliminate a lot of bugs. I'm not aware of any language or standard library that does this, though.)
&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;You should checkout Haskell's newtype operator and Scala's AnyVal that allow for this. Basically 0-cost at runtime types that don't let you mix during compile time.</description><guid isPermaLink="true">7c86ab95a1618b3f295a193793db8ef3</guid><pubDate>Tue, 10 Nov 2015 03:00:21 GMT</pubDate></item><item><title>Josh Ballanco - 2015-11-08 04:18:22</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>&lt;div class="blogcommentquote"&gt;&lt;div class="blogcommentquoteinner"&gt;I think that having different conceptual kinds of strings be distinct types would eliminate a lot of bugs. I'm not aware of any language or standard library that does this, though.&lt;/div&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;Another, more recent, language that does this is Julia with its "Non-Standard String Literals": &lt;a href="http://docs.julialang.org/en/release-0.4/manual/metaprogramming/#man-non-standard-string-literals2"&gt;http://docs.julialang.org/en/release-0.4/manual/metaprogramming/#man-non-standard-string-literals2&lt;/a&gt; . It takes Python's &lt;code&gt;r"foo.*bar"&lt;/code&gt; syntax for regexes and extends it in a user-definable way. For example, &lt;code&gt;v"1.1.0"&lt;/code&gt; creates a &lt;code&gt;VersionNumber&lt;/code&gt;.</description><guid isPermaLink="true">f10907e21cd0eb9447be6ce139ebb5c7</guid><pubDate>Sun, 08 Nov 2015 04:18:22 GMT</pubDate></item><item><title>mikeash - 2015-11-08 03:12:20</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>I don't know if Swift cares much about interning strings. It does care a lot about using them as dictionary keys, though, which has essentially the same performance requirements.
&lt;br /&gt;
&lt;br /&gt;I think this approach would fit that well, simply because the implementation details are completely hidden, so &lt;code&gt;String&lt;/code&gt; is free to use whatever internal representation makes the most sense for this. Contrast with &lt;code&gt;NSString&lt;/code&gt;, where an internal representation using (say) UTF-32 would conflict badly with the API. Whatever internal representation makes the most sense for hashing, &lt;code&gt;String&lt;/code&gt; could use it.</description><guid isPermaLink="true">bb528a430744a8650018c1ffc0471eaa</guid><pubDate>Sun, 08 Nov 2015 03:12:20 GMT</pubDate></item><item><title>Anthony Bailey - 2015-11-07 15:21:23</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>This is one of those "nice clear expression of how I fuzzily thought things should be" blog posts that I really enjoy and appreciate. Thanks!
&lt;br /&gt;
&lt;br /&gt;Does the approach fit nicely with another real-world concern - a time/space-efficient implementation of string interning? Or is that kind of optimization outside of Swift's intended domain?</description><guid isPermaLink="true">e24f4e7167e636afaddbfbb01109518b</guid><pubDate>Sat, 07 Nov 2015 15:21:23 GMT</pubDate></item><item><title>Pierre Lebeaupin - 2015-11-07 10:43:39</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>re: "you can't always avoid it", I am trying to define a set of minimal primitives (with any other operation expressed as convenience methods over these primitives) for the string type to support all non-specialist text operations such that peeking at the components is never necessary:
&lt;br /&gt;* defining literal ASCII strings (typically for dictionary keys and debugging)
&lt;br /&gt;* reading and writing strings from byte arrays with a specified encoding
&lt;br /&gt;* printing the value of variables to a string, possibly under the control of a format and locale
&lt;br /&gt;* attempting to interpret the contents of a string as an integer or floating-point number, possibly under the control of a format and locale
&lt;br /&gt;* concatenating strings
&lt;br /&gt;* hashing strings (with an implementation of hashing that takes into account the fact strings that only vary in character composition are considered equal and so must have equal hashes)
&lt;br /&gt;* searching within a string with appropriate options (regular expression or not, case sensitive or not, anchored or not, etc.) and getting the first match (which may compare equal while not being the exact same Unicode sequence as the searched string), the part before that match, and the part after that match, or nothing if the search turned empty.
&lt;br /&gt;* comparing strings for equality and sorting with appropriate options (similar to that of searching, plus specific options such as numeric sort, that is "1" &amp;lt; "2" &amp;lt; "100")
&lt;br /&gt;* and for very specific purposes, a few text transformations: mostly convert to lowercase, convert to uppercase, and capitalize words.
&lt;br /&gt;
&lt;br /&gt;Though I probably need to add string folding with the same options as comparing for equality (in order to use the folded strings as keys to a dictionary, for instance).
&lt;br /&gt;
&lt;br /&gt;I have yet to hear of an ordinary text operation that cannot be factored as a combination of these primitives.
&lt;br /&gt;
&lt;br /&gt;But what about text editing operations, typesetting, text rendering, full-text indexing, figuring word boundaries, word breaks, etc? Those are to be implemented by specialists who write libraries providing these services and ordinary programmers are to use the APIs of these libraries. Yes, even "translating" to pig latin is such a specialist operation, because you have to think first about what it means for Chinese text, for instance.</description><guid isPermaLink="true">6174e64ee1dcb996a99e97b8d6581c76</guid><pubDate>Sat, 07 Nov 2015 10:43:39 GMT</pubDate></item><item><title>mikeash - 2015-11-07 02:03:32</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>&lt;b&gt;araybould:&lt;/b&gt; Gotcha, and yes, I just meant it in the sense that allowing [integer] would be misleading, but not that leaving it out somehow explains the limitations.
&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;Josh Bleecher Snyder:&lt;/b&gt; "It's important to state right up front that a string holds arbitrary bytes. It is not required to hold Unicode text, UTF-8 text, or any other predefined format. As far as the content of a string is concerned, it is exactly equivalent to a slice of bytes." And their very first example shows a string literal that does not contain valid UTF-8. Am I missing something here?</description><guid isPermaLink="true">73dee0a51a6b60d3b6c5c0b8b73e2786</guid><pubDate>Sat, 07 Nov 2015 02:03:32 GMT</pubDate></item><item><title>Josh Bleecher Snyder - 2015-11-07 01:56:12</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>In Go, strings are UTF8 sequences, not byte sequences, even though indexing into a string returns the nth byte. See &lt;a href="https://blog.golang.org/strings"&gt;https://blog.golang.org/strings&lt;/a&gt;.</description><guid isPermaLink="true">f73ad40dd7026c661a7dc4f43937f384</guid><pubDate>Sat, 07 Nov 2015 01:56:12 GMT</pubDate></item><item><title>Keith Thompson - 2015-11-07 00:48:09</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>&lt;div class="blogcommentquote"&gt;&lt;div class="blogcommentquoteinner"&gt;In C, a string is a pointer to a sequence of non-zero bytes, terminated by a zero byte.&lt;/div&gt;&lt;/div&gt;
&lt;br /&gt;Not quite.  In C, a string is by definition "a contiguous sequence of characters terminated by and including the ﬁrst null character". Strings are manipulated using pointers, but the pointer itself is not the string; it's a &lt;i&gt;pointer to a string&lt;/i&gt;.
&lt;br /&gt;
&lt;br /&gt;Reference: &lt;a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf"&gt;http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf&lt;/a&gt; 7.1.1p1</description><guid isPermaLink="true">f92dbe664ec0b4ca090e45f87d8bc994</guid><pubDate>Sat, 07 Nov 2015 00:48:09 GMT</pubDate></item><item><title>Eelco - 2015-11-07 00:38:12</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>Re: different string types, this is a great article (from almost a decade ago!) on how to achieve this in Haskell: &lt;a href="http://blog.moertel.com/posts/2006-10-18-a-type-based-solution-to-the-strings-problem.html"&gt;http://blog.moertel.com/posts/2006-10-18-a-type-based-solution-to-the-strings-problem.html&lt;/a&gt;</description><guid isPermaLink="true">735d57c52b919ca6631e820a0e034043</guid><pubDate>Sat, 07 Nov 2015 00:38:12 GMT</pubDate></item><item><title>ttilley - 2015-11-07 00:23:32</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>...and normal people can ignore the null check. I need it for my particular use case for unrelated reasons. </description><guid isPermaLink="true">5192853b1efec288c3e7f696d1068b00</guid><pubDate>Sat, 07 Nov 2015 00:23:32 GMT</pubDate></item><item><title>ttilley - 2015-11-07 00:05:21</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>you can use hidden functionality to convert UTF16 arrays. here is an example from my project (UChar is an alias pulled in from C, its a single UTF16 value):
&lt;br /&gt;
&lt;br /&gt;&lt;code&gt;
&lt;br /&gt;internal func ucharCollectionToString&amp;lt;T:CollectionType where T.Generator.Element == UChar&amp;gt;(collection: T) -&amp;gt; String {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;let count = collection.underestimateCount()
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var sc = _StringCore.init()
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sc.reserveCapacity(count)
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for codeunit in collection {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// terminate processing at NULL like C string behavior
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if codeunit != UChar(0) {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sc.append(codeunit)
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} else { break }
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return String(sc)
&lt;br /&gt;}
&lt;br /&gt;&lt;/code&gt;
&lt;br /&gt;
&lt;br /&gt;I'm pretty sure this is going to be much faster than transcoding before creating your string object, but it depends on an internal API.</description><guid isPermaLink="true">35670aabc88077a392e03e639ef42407</guid><pubDate>Sat, 07 Nov 2015 00:05:21 GMT</pubDate></item><item><title>araybould - 2015-11-06 23:18:41</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description> @mikeash: My mistake - when I wrote the last reply I was still thinking that "why not make it easier, and allow indexing with an integer? It's essentially Swift's way of reinforcing the fact that this is an expensive operation" was intended to imply that programmers would deduce, from the absence of the operation, that it would be expensive. I see now that your point is that in the presence of the operation, many programmers would assume that it is efficient. I was wrongly thinking the contrapositive was implied, but programmers are not necessarily assuming anything from the operator's absence. I imagine some of them will go on to use advancedBy() inefficiently, but at least they are warned. 
&lt;br /&gt;</description><guid isPermaLink="true">b3b6d593c3fffea9c2409de64a487963</guid><pubDate>Fri, 06 Nov 2015 23:18:41 GMT</pubDate></item><item><title>mikeash - 2015-11-06 22:14:31</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>&lt;b&gt;Pierre Lebeaupin:&lt;/b&gt; Thanks for pointing out the mistake with the accent. I don't know what happened there. Maybe I had some temporary brain damage. (I can hear everybody now, "What do you mean, 'temporary'?")
&lt;br /&gt;
&lt;br /&gt;And yes, you're right, avoid actually peeking at the components of the string whenever you can. Unfortunately you can't always avoid it, because the APIs aren't always there for you, but definitely look real hard first.
&lt;br /&gt;
&lt;br /&gt;Note that with Twitter, you need to count code points but first you need to normalize the string, so that's a bit of an extra complication there. Unfortunately Swift doesn't provide anything for normalization at the moment, although you can use the NSString APIs for it.</description><guid isPermaLink="true">e89369e4043a991335d6b0e64a062c53</guid><pubDate>Fri, 06 Nov 2015 22:14:31 GMT</pubDate></item><item><title>Matt - 2015-11-06 21:59:23</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>Thanks for this write up. I'm not a Swift programmer whatsoever and still found it useful and interesting.</description><guid isPermaLink="true">4bef708e73dbbc68819174922ea0f2d5</guid><pubDate>Fri, 06 Nov 2015 21:59:23 GMT</pubDate></item><item><title>Pierre Lebeaupin - 2015-11-06 21:35:45</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>First, there is a small mistake: the third Unicode code point of your example string in "problems" is not U+00B4 (ACUTE ACCENT), but U+0301 (COMBINING ACUTE ACCENT), among other things we can see it encodes to 0xCC 0X81 in UTF-8 (not to mention that this accent… combines, you know). Also, the last possible Unicode code point (so as to be encodable with two surrogates) is at U+10FFFF, you may need more than 20 bits (five nibbles), so I never represent "A" as 0x00041 or U+00041, rather 0x000041 (or 0x0041 if dealing with UTF-16 or 0x41 if dealing with UTF-8), because, granted, 0x00000041 or U+00000041 is a bit too long…
&lt;br /&gt;
&lt;br /&gt;I argue (at &lt;a href="http://wanderingcoder.net/2015/07/24/string-character-processing/"&gt;http://wanderingcoder.net/2015/07/24/string-character-processing/&lt;/a&gt; among others) that ordinary programmers need never care about the individual constituent of a string. Doesn't matters if you consider a string to be a sequence of bytes, words, code points, graphemes clusters: simply don't. Need to move the insertion point? Send the advanceInsertionPoint/moveBackInsertionPoint message to the text editing engine, it is going to worry about what that means, not you. A tweet? Serialize the string to a byte array with the UTF-32BE encoding (I haven't checked what the Twitter API takes, to be honest; adapt as appropriate), divide the length of the byte array by 4, that will give you whether you are at less, more, or exactly at 140. Database column? Same, except the encoding it UTF-8, and again you check if the byte array fits. Need to check whether the file name has extension "avi"? Do a case-insensitive, anchored, reverse, locale-independent search for ".avi" in the file name string. etc.
&lt;br /&gt;
&lt;br /&gt;As a result, I completely agree with the Swift design of opaque indexes from string. Besides saving you from quadratic algorithms, it forces you to think about what it is you are actually doing to the string.
&lt;br /&gt;
&lt;br /&gt;I am surprised that Swift still does not have a way to create a string by decoding a byte array in a specified encoding, and to create a byte array in a specified encoding from a string as part of the type. In particular, these UTF-x views should only be though as ways to integrate with foreign APIs (and as first step to decode from/encode to a byte array, since there is no direct way to do so), not means in and of themselves. Python 3 has the right idea (though I think it does not go far enough): there is no character type, merely very short strings when one does character-like processing, and the encodings (UTF-8, UTF-16, UTF-32) are only that: encodings that you can specify when decoding from/encoding to a byte array (for a file, network packet, etc.) </description><guid isPermaLink="true">dfc82205e5b28900213693fe810557e1</guid><pubDate>Fri, 06 Nov 2015 21:35:45 GMT</pubDate></item><item><title>coldtea - 2015-11-06 20:42:22</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>&amp;gt; I think that having different conceptual kinds of strings be distinct types would eliminate a lot of bugs. I'm not aware of any language or standard library that does this, though.)
&lt;br /&gt;
&lt;br /&gt;Rebol does that.</description><guid isPermaLink="true">2eae1bafc8d93c53e82e504e8a686617</guid><pubDate>Fri, 06 Nov 2015 20:42:22 GMT</pubDate></item><item><title>mikeash - 2015-11-06 20:38:18</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>&lt;b&gt;araybold:&lt;/b&gt; I'm not sure what you're referring to. Which implication is clear, and what "it" are people not getting?</description><guid isPermaLink="true">a42d45d810bb55b155f5e3ada11710b6</guid><pubDate>Fri, 06 Nov 2015 20:38:18 GMT</pubDate></item><item><title>araybold - 2015-11-06 20:25:09</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>@Jon: tanks for the links.
&lt;br /&gt;
&lt;br /&gt;@mikeash: I am not sure if it entirely consistent to say that the implication is clear, while also providing a detailed explanation here - does that not imply that you think some people are not, in fact, getting it?</description><guid isPermaLink="true">607710ba4fd5091f70e8d2becae4dffc</guid><pubDate>Fri, 06 Nov 2015 20:25:09 GMT</pubDate></item><item><title>Marc P. - 2015-11-06 18:57:01</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>It seems like the NSString bridging is helped along by a hidden String implementation &lt;code&gt;_SwiftNativeNSStringBase&lt;/code&gt;, which bodes poorly for the imminent Linux port of Swift, since the absence of an accompanying Foundation port will leave the String implementation non-performant when it needs to work with real-world encodings like UTF-8 and UTF-16.
&lt;br /&gt;
&lt;br /&gt;Thanks for the tip about testing with optimization; it does help out the string performance quite a bit. But I don't think that the calling of the user-supplied block accounts for most of the overhead. The transcode() function be manually performed without any blocks like so:
&lt;br /&gt;
&lt;br /&gt;&lt;code&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;func testUTF16StringConversion() {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var str = ""
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;measureBlock {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var string = ""
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var utf16 = UTF16()
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var gen = utf16Array.generate()
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var done = false
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while !done {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;switch utf16.decode(&amp;amp;gen) {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case .Result(let val): string.append(val)
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case .EmptyInput: done = true
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case .Error: fatalError("bad string")
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;str = string
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;XCTAssertEqual(Array(str.utf16), utf16Array)
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;&lt;/code&gt;
&lt;br /&gt;
&lt;br /&gt;This method gives about a 15% boost to the extension where transcode() is being invoked, but it is still a far cry from the internal optimization that the &lt;code&gt;NSString&lt;/code&gt; conversion gives you.
&lt;br /&gt;
&lt;br /&gt;OTOH, &lt;code&gt;NSString&lt;/code&gt;'s constructor almost certainly is not doing any validation of the byte array, so it's not an entirely fair comparison. But it would be nice to have a fast-track mechanism to create a String from a sequence of encoded bytes available in Swift.</description><guid isPermaLink="true">fc928d7b84232bbfb571681409b90e82</guid><pubDate>Fri, 06 Nov 2015 18:57:01 GMT</pubDate></item><item><title>mikeash - 2015-11-06 18:39:12</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>&lt;b&gt;ARaybold:&lt;/b&gt; I think that if any programmer sees this, they will assume that it's O(1):
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;someVar1[someVar2]
&lt;br /&gt;
&lt;br /&gt;On the other hand, they will not assume any particular performance for this:
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;someVar1.advancedBy(someVar2)
&lt;br /&gt;
&lt;br /&gt;Yes, this doesn't tell you what the performance actually &lt;i&gt;is&lt;/i&gt;, but it at least doesn't lead you to make assumptions. (Note that in Swift, the [] indexing operation is still fast. The cost is in getting the right index value to pass to it.)
&lt;br /&gt;
&lt;br /&gt;As far as the documentation goes, command-click a Swift symbol in Xcode and then read through all the comment documentation in the Swift module. The same information is also available on &lt;a href="http://swiftdoc.org"&gt;http://swiftdoc.org&lt;/a&gt;, and from Apple at &lt;a href="https://developer.apple.com/library/ios/documentation/Swift/Reference/Swift_ForwardIndexType_Protocol/index.html"&gt;https://developer.apple.com/library/ios/documentation/Swift/Reference/Swift_ForwardIndexType_Protocol/index.html&lt;/a&gt;. The documentation for advancedBy explicitly states that the complexity is O(1) on a RandomAccessIndexType, and O(n) otherwise.</description><guid isPermaLink="true">d2ca4d024c1c9dcf1aee94b16338bb39</guid><pubDate>Fri, 06 Nov 2015 18:39:12 GMT</pubDate></item><item><title>Jon - 2015-11-06 18:36:38</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>ARaybold: Most of the documentation for the Swift core language exists in the library "header" files. You can check them out, rendered in a nice, searchable website, at swiftdoc.org.</description><guid isPermaLink="true">cfd207c01ba6ab38c07f695f358789d5</guid><pubDate>Fri, 06 Nov 2015 18:36:38 GMT</pubDate></item><item><title>ARaybold - 2015-11-06 17:28:10</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>It may seem odd that I read this despite never having written a line of Swift code, and not likely to do so in the near future at least, but it is an interesting case of API design.
&lt;br /&gt;
&lt;br /&gt;I think you make a good case, but this got my attention: "Why not make it easier, and allow indexing with an integer? It's essentially Swift's way of reinforcing the fact that this is an expensive operation."
&lt;br /&gt;
&lt;br /&gt;This is a pretty indirect way of making the point. Perhaps the documentation for advancedBy() contains that warning? I went to the Apple Developer web site and searched around for a while, but not only did I not find a statement to this effect, I did not even find a concise reference document covering string functions, operators and methods. Maybe someone who has spent even a little more time with Swift than I have will have stumbled upon (and bookmarked) the sort of documentation that a programmer will need, but I am (for now) left with the impression that the underlying problem here is a failure to communicate.
&lt;br /&gt;
&lt;br /&gt;Your article here also indirectly makes a good counter-example against the proposition that code can be adequately self-documenting, as it shows some real-world examples of where a function name cannot convey all the information you need to know to use it properly.
&lt;br /&gt;&amp;nbsp;</description><guid isPermaLink="true">5a51e4854e501931baf4b9a5e6728395</guid><pubDate>Fri, 06 Nov 2015 17:28:10 GMT</pubDate></item><item><title>mikeash - 2015-11-06 16:43:12</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>&lt;b&gt;Marc P:&lt;/b&gt; Good question. I think the &lt;code&gt;transcode&lt;/code&gt; function is just too general to be very fast. Calling a user-supplied function for every code point is tough to optimize. Which is all the more reason the standard library ought to provide a direct initializer for &lt;code&gt;String&lt;/code&gt; that takes UTF-8 and UTF-16.
&lt;br /&gt;
&lt;br /&gt;Do make sure you have optimizations enabled when testing, though. Swift is still slower, but it speeds up by about a factor of 10. Also, it depends pretty heavily on the encoding and the data. UTF-16 is &lt;code&gt;NSString&lt;/code&gt;'s native encoding, so creating an &lt;code&gt;NSString&lt;/code&gt; from a UTF-16 array is basically just a &lt;code&gt;memcpy&lt;/code&gt;. Try with UTF-8 and a Unicode flag as the repeated &lt;code&gt;Character&lt;/code&gt; and while Swift still loses the race, it "only" loses by a factor of 3-4 instead of a factor of a bazillion.</description><guid isPermaLink="true">a26571b5e82184ea69f622b55fc59844</guid><pubDate>Fri, 06 Nov 2015 16:43:12 GMT</pubDate></item><item><title>Anon - 2015-11-06 16:35:04</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>"(Incidentally, I think that representing all these different concepts as a single string type is a mistake. Human-readable text, file paths, SQL statements, and others are all conceptually different, and this should be represented as different types at the language level. I think that having different conceptual kinds of strings be distinct types would eliminate a lot of bugs. I'm not aware of any language or standard library that does this, though.)"
&lt;br /&gt;
&lt;br /&gt;A lot of languages provide the ability to create types easily though. Go-lang comes to mind. Of course in an OO language you could make a class for each type of string but that would be a bit much I think most sane people would agree.</description><guid isPermaLink="true">1804eea3ec86aba685cae2f90993f646</guid><pubDate>Fri, 06 Nov 2015 16:35:04 GMT</pubDate></item><item><title>Marc P - 2015-11-06 16:04:18</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>Is there any way to approach the native NSString bridging performance in pure-Swift? If I compare creating a string using your UTF-16 extensions with that of constructing an NSString with the bytes, the NSString constructing is two orders of magnitude faster.
&lt;br /&gt;
&lt;br /&gt;Here are the test cases I used:
&lt;br /&gt;
&lt;br /&gt;&lt;code&gt;
&lt;br /&gt;// a very big UTF-16 array
&lt;br /&gt;let utf16Array = Array(String(count: 999999, repeatedValue: Character("X")).utf16)
&lt;br /&gt;
&lt;br /&gt;class StringPerformanceTests: XCTestCase {
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;func testMikeAshStringConversionPerformance() {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var str = ""
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;measureBlock {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;str = String(utf16: utf16Array)!
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;XCTAssertEqual(Array(str.utf16), utf16Array)
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;func testNSStringConversionPerformance() {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var str = ""
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;measureBlock {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;str = utf16Array.withUnsafeBufferPointer { ptr in
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NSString(characters: ptr.baseAddress, length: ptr.count) as String
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;XCTAssertEqual(Array(str.utf16), utf16Array)
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;}
&lt;br /&gt;
&lt;br /&gt;&lt;/code&gt;
&lt;br /&gt;</description><guid isPermaLink="true">5b975a876f3c48b9ee1f3899527aca8e</guid><pubDate>Fri, 06 Nov 2015 16:04:18 GMT</pubDate></item><item><title>mikeash - 2015-11-06 15:33:06</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>&lt;b&gt;Gerard Guillemette:&lt;/b&gt; Yes, that is really nice. Even NSString doesn't do that by default.
&lt;br /&gt;
&lt;br /&gt;&lt;code&gt;stringA as NSString == stringB as NSString // false&lt;/code&gt;
&lt;br /&gt;
&lt;br /&gt;You have to use one of the more specific comparison methods to make that say true.
&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;calicoding:&lt;/b&gt; As I said, I think it's a mistake to have "path" be the same type as other kinds of text, so I think moving paths over to &lt;code&gt;NSURL&lt;/code&gt; is a pretty good thing. Of course, we end up with a similar problem where, where &lt;code&gt;NSURL&lt;/code&gt; can contain arbitrary URLs with arbitrary schemes, but 99% of the framework methods that take an &lt;code&gt;NSURL&lt;/code&gt; only accept &lt;code&gt;file:&lt;/code&gt; URLs. Note that the path methods are still available if you use &lt;code&gt;as NSString&lt;/code&gt; to get an explicit &lt;code&gt;NSString&lt;/code&gt; first. Then they return &lt;code&gt;String&lt;/code&gt; so it's a bit annoying, but the functionality is at least still there.</description><guid isPermaLink="true">04ce2c0e701ad2043f74f46dd98abf27</guid><pubDate>Fri, 06 Nov 2015 15:33:06 GMT</pubDate></item><item><title>calicoding  - 2015-11-06 15:15:30</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>I would also add that swift's API did not bring over all the "path" methods of NSString, which seems to be a pain point for a lot of people. But here Apple is trying to reduce the scope of the problem and have people just use NSURL instead. This seems reasonable to me, and to be honest, more correct.
&lt;br /&gt;
&lt;br /&gt;Ps. Great stuff as always</description><guid isPermaLink="true">5dcb8b3d5ee3867155d58bc9e8193205</guid><pubDate>Fri, 06 Nov 2015 15:15:30 GMT</pubDate></item><item><title>Gerard Guillemette - 2015-11-06 14:49:25</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html#comments</link><description>It was pointed out in "The Swift Apprentice" that Swift does the right thing with something like
&lt;br /&gt;
&lt;br /&gt;let stringA = "café"
&lt;br /&gt;let stringB = "cafe\u{0301}"
&lt;br /&gt;let equal = stringA == stringB
&lt;br /&gt;
&lt;br /&gt;In stringA the bytes are 99-97-102-233 while for the second it is 99-97-102-101-769.  "equal" ends up being true despite the difference in representation of é.</description><guid isPermaLink="true">848c1905a86f8896e1c0961c7950a196</guid><pubDate>Fri, 06 Nov 2015 14:49:25 GMT</pubDate></item></channel></rss>
