[swift-evolution] Strings in Swift 4

Dave Abrahams dabrahams at apple.com
Tue Jan 24 12:26:57 CST 2017

on Fri Jan 20 2017, Jonathan Hull <jhull-AT-gbis.com> wrote:

>> On Jan 20, 2017, at 8:28 AM, Dave Abrahams <dabrahams at apple.com> wrote:
>>> On Jan 20, 2017, at 5:48 AM, Jonathan Hull <jhull at gbis.com <mailto:jhull at gbis.com>> wrote:
>>> Thanks for all the hard work!
>>> Still digesting, but I definitely support the goal of string processing even better than Perl.
> Some random thoughts:
>>> • I also like the suggestion of implicit conversion from substring
> slices to strings based on a subtype relationship, since I keep
> running into that issue when trying to use array slices.
>> Interesting.  Could you offer some examples?
> Nothing catastrophic.  Mainly just having to wrap all of my slices in
> Array() to actually use them, which obfuscates the purpose of my
> code. It also took me an embarrassingly long time to figure out that
> was what I had to do to make it work.  

Is this because you're calling Cocoa APIs that traffic in Array?  An
alternative is to make such APIs generic on Collection instead of

> For the longest time, I couldn’t understand why anyone would use
> slices because I couldn’t actually use them with any API… and then
> someone mentioned wrapping it in Array() here on Evolution and I
> finally got it.  Though it still feels like internal details that I
> shouldn’t have to worry about leaking out...

Because they have a very real performance impact, they're not strictly
internal details.

>>> It would be nice to be able to specify that conversion behavior with
>>> other types that have a similar subtype relationship.
>> Indeed.
>>> • One thing that stood out was the interpolation format syntax, which seemed a bit convoluted and
> difficult to parse:
>>>> "Something with leading zeroes: \(x.format(fill: zero, width:8))"
>>> Have you considered treating the interpolation parenthesis more
> like the function call syntax?  It should be a familiar pattern and
> easily parseable to someone versed in other areas of swift:
>>>   “Something with leading zeroes: \(x, fill: .zero, width: 8)"
>> Yes, we've considered it
>>  1. "\(f(expr1, label2: expr2, label3: expr3))" 
>>     String(describing: f(expr1, label2: expr2, label3: expr3))
>>  2. "\(expr0 + expr1(label2: expr2, label3: expr3))"
>>     String(describing: expr0 + expr1(label2: expr2, label3: expr3)
>>  3. "\((expr1, label2: expr2, label3: expr3))"
>>     String(describing: (expr1, label2: expr2, label3: expr3))
>>  4. "\(expr1, label2: expr2, label3: expr3)"
>>     String(describing: expr1, label2: expr2, label3: expr3)
>> I think I'm primarily concerned with the differences among cases 1, 3,
>> and 4, which are extremely minor.  3 and 4 differ by just a set of
>> parentheses, though that might be mitigated by the ${...} suggestion someone else posted.  The
> point of using string interpolation is to improve
>> readability, and I fear these cases make too many things look alike that
>> have very different meanings.  Using a common term like "format" calls
>> out what is being done.
>> It's possible to produce terser versions of the syntax that don't suffer
>> from this problem by using a dedicated operator:
>>  "Column 1: \(n⛄(radix:16, width:8)) *** \(message)"
>>  "Something with leading zeroes: \(x⛄(fill: zero, width:8))"
>> or even
>>  "Column 1: \(n⛄radix:16⛄width:8) *** \(message)"
>>  "Something with leading zeroes: \(x⛄fill:zero⛄width:8)”
> There is still too much going on here to be readable, though I suppose
> you could put part of it on a previous line.  I really like Joe’s
> suggestion of how to handle this using an
> ExpressableByStringInterpolation protocol + sugar.  One of my favorite
> things about the current \() is how readable it makes my strings
> compared to every other language I have used!  I definitely want to
> make sure we keep that advantage...


>>> I think that should work for the common cases (e.g. padding,
> truncating, and alignment), with string-returning methods on the type
> (or even formatting objects ala NSNumberFormatter) being used for more
> exotic formatting needs (e.g. outputting a number as Hex instead of
> Decimal)
>>> • Have you considered having an explicit .machine locale which
> means that the function should treat the string as machine readable?
> (as opposed to the lack of a locale)
>> No, we hadn't.  What would be the goal of such a design?
> Just to be able to explicitly spell the desired behavior (as opposed
> to only being able to rely on the lack of something).  The end usage
> would most likely be the same in most places as .machine could
> probably be the default value of the ‘locale’ parameter.  However, it
> would allow me to express my intention to other programmers (and
> future Jon) that this function is explicitly handling the string as
> machine readable.  It is a difference in feeling and expression as
> opposed to a difference in ability.

I think we still want to be able to call sort() on an Array<String>
without providing a predicate, which means there *will* be some default
comparison behavior.

> Also, it may help future proof a bit.  If we do end up adding the
> concept of “human readable” strings down the line, one could see the
> current locale being a really good default for them. There may still
> be times where you want to override that and treat them as machine
> readable for one reason or another.  Having .machine allows you to
> make that override explicitly, while still providing the reasonable
> default.

I think if we have HumanReadableString one day we'll want a lightweight
way to convert between it and String, so people can just use that.

>>> • I almost feel like the machine readableness vs human readableness
>>> of a string is information that should travel with the string
>>> itself. It would be nice to have an extremely terse way to specify
>>> that a string is localizable (strawman syntax below), and that might
>>> also classify the string as human readable.
>>> let myLocalizedStr = $”This is localizable” //This gets used as the comment in the localization
>>> file
>> Yes, there are also arguments for encoding "human readable" in the
>> type system.  But as noted in
>> https://github.com/apple/swift/blob/master/docs/StringManifesto.md#future-directions
>> <https://github.com/apple/swift/blob/master/docs/StringManifesto.md#future-directions>
>> those ideas are scoped out of Swift 4.
> Yes, I could see that too.  I guess the main question is: Do we want
> to be able to add methods that apply ONLY to human readable strings?
> If so, then encoding it in the type system makes more sense.

Well, there exist lots of APIs that should only accept human-readable
strings, e.g. setting the title of a button.


More information about the swift-evolution mailing list