Why string interpolation?

With all this talk of raw strings and string interpolation improvements, I can't help but ask this. Please don't throw stones. Why does Swift have string interpolation at all, rather than say a type of "string concatenation". (Yes, I know Swift supports the + operator for two strings, but I am talking something like this:

extension String {
    public static func || (lhs: String, rhs: Any) -> String {
        return lhs + String(describing: rhs)
    }
}

let myField = "test"

let s1 = "Name:\u{0009}myField\nvalue:\t\"\(myField)\""
let s2 = "Name:"||"\u{0009}"||"myField"||"\n"||"value:"||"\t\""||myField||"\""
print(s1)
print(s2)
print("s1 == s2: " + String(s1 == s2))

With some new style of "escape characters", such as \u{#####} for Unicode and \{c} for "C-ish style" escape values, s2 could be something like this:

"Name:"||\u{0009}||"myField"||\{n}||"value:"||\{t"}||myField||\{"}

I personally find this to be more readable, at the expense of being a bit more verbose than string interpolation. With spaces between the concat operator it's even more readable.

"Name:" || \u{0009} || "myField" || \{n} || "value:" || \{t"} || myField || \{"}

I guess it doesn't truly resolve the need for raw strings, but it just got me wondering.

No, I don't expect Swift to be changed at this point! But I would be interested in the answer to my question above.

1 Like

At a technical level, it's important that we recognize interpolations early—before we need to resolve operator overloads—and treat them specially. The type checker slows down and, eventually, errors out if an expression is too complex; if it didn't recognize interpolations and handle them specially, it wouldn't be able to handle more than a handful of interpolations in a single literal.

At a comprehension level, I find the dense punctuation in your example extremely unreadable. The difference between "||", "||, and ||" is very important, but easy to miss. In your example, the fact that the first "myField" is text but the second is an expression is super-important; how easy is it for you to tell that?

And at an aesthetic level, I find the s1 line to look much nicer than the s2 line. It looks like a string literal with some computed parts, not an expression which produces a string. And if you use a multiline string literal (which would work very poorly with your suggestion, by the way), it can be even nicer, an almost perfect picture of what you'll get at runtime:

let s3 = """
         Name:	myField
         value:	"\(myField)"
         """
3 Likes

Thanks Brent.

I'll agree that the first example of s2 is pretty hard to read. I thought of giving an example of what it would be like with a judicious use of space characters, but since it wasn't my "final example" I decided not to. Anyway:

let s2 = "Name:" || "\u{0009}" || "myField" || "\n" || "value:" || "\t\"" || myField || "\""

To me that's pretty readable. And again, my final example with spaces and "new escapes" even more so (IMO).

Anyhow, your answer makes sense, and I think you for explaining it.

FWIW, my example is a strawman example; I just happened to use tabs and newline because I couldn't think of a better example. (Your solution doesn't use tabs, btw.) But I agree, my idea wouldn't work well (or at all) with multi-line strings. I had not even considered multi-line strings.

I will find the backslashes "smashed" against the literal text hard to read, but I suppose I'll get used to it.
Thanks again!

1 Like

It does, but it uses the tab character directly instead of the \t escape.

Very sneaky!