So, everyone knows what a string interpolation looks like:
print("Hello, \(firstName)!")
But let's talk about some other things you might write, perhaps because you hate compiler engineers. What do you think these do?
print("Hello, \()!") // #1
print("Hello, \(first: firstName)!") // #2
print("Hello, \(firstName, lastName)!") // #3
print("Hello, \(first: firstName, last: lastName)!") // #4
Most people I've spoken to say "produce an error message", and they're right about #1—it produces the error "expected expression in list of expressions". Maybe not the clearest message, but it's not technically wrong.
But the other three? They actually compile without complaint and form a tuple. So #2, #3, and #4 above are equivalent to writing:
print("Hello, \((first: firstName))!")
print("Hello, \((firstName, lastName))!")
print("Hello, \((first: firstName, last: lastName))!")
(Why isn't #1 equivalent to print("Hello, \(())!")
? Because of an odd inconsistency in string interpolation parsing. Long story.)
#2 forms a single-element tuple which somehow doesn't get diagnosed, but whatever, those sneak through sometimes. (Currently, #2 sometimes causes mischief; I'm working on that.) But #3 and #4 are vaguely reasonable things to do. On the other hand, they're not documented, and at least #3 can confuse people—the only person I've talked to who didn't assume it was an error guessed "maybe it concatenates them with a space between, like print()
."
What should we do?
Well, our default should be to preserve source compatibility:
- Probably keep #1 the same, perhaps changing the error message.
- Either keep the current behavior of #2, silently remove the label during parsing, or perhaps emit a warning and fix-it. (I assume source compatibility keeps us from making this a hard error.)
- Keep the current behavior of #3 and #4.
If we keep the current behavior, we should probably document it. The syntax currently happens to work because of a quirk of the parser's implementation; if it's not documented, people will keep being surprised.
But I would prefer to deprecate #2, #3, and #4 with warnings and fix-its in Swift 4.2. #2 is an outright bug; #3 and #4 have counter-intuitive semantics, have never been documented or tested, and examples of them are rare at best. The fix—add an extra set of parentheses—is trivial to apply. And I'd really like to use this syntax in Swift 5 for some flexible new string interpolation features which might, for instance, allow us to implement the print()
-like behavior that the only person who didn't think it was an error guessed it might have.
Thoughts?