[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
Array-specific.

> 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...

+1

>>> 
>>> 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.


-- 
-Dave


More information about the swift-evolution mailing list