[swift-evolution] multi-line string literals.

Brent Royal-Gordon brent at architechies.com
Mon Apr 25 19:22:48 CDT 2016


>> * Disabling escapes: If you use single quotes instead of double quotes, backslash escapes are disabled.
> 
> We need a way to disable escapes, but it seems to me that (since it is orthogonal to the other concerns) that it should not be tied to the “multiple single quotes” syntax.  What is your thought on “modifier” prefix characters for string literals?  e.g.:
> 
> 	let x = e”no \escapes \(processed here”
> 
> If we supported these, they would be supported with multi-line string literals by putting the modifiers on the first line of the literal, and the multi-line approach above would “just work”.  You could introduce several different modifiers, e.g. one that disabled general escapes, but still allowed \(x) for substitution.  
> 
>> 3. It might be useful to make multiline `"` strings trim trailing whitespace and comments like Perl's `/x` regex modifier does.
> 
> If you have modifier characters already, it is easy to build a small zoo full of these useful beasts.

Modifiers are definitely a workable alternative, and can be quite flexible, particularly if a future macro system can let you create new modifiers.

(The Perl script I just posted about supports the e"" syntax you're proposing.)

>> * Yes, with a number of backslashes matching the number of quotes, which allows you to insert literal \( text: '''		<author>\\\(author)</author>
> 
> Egads!

Yeah, that's a little more clever than nice. :^)

>> * Alternative delimiters: If a string literal starts with three, or five, or seven, or etc. quotes, that is the delimiter, and fewer quotes than that in a row are simply literal quote marks. Four, six, etc. quotes is a quote mark abutting the end of the literal.
>> 
>> 	let xml: String = """<?xml version="1.0"?>
>> 				"""<catalog>
>> 				"""\t<book id="bk101" empty="">
>> 				"""\t\t<author>\(author)</author>
>> 				"""\t</book>
>> 				"""</catalog>"""
>> 
>> You can't use this syntax to express an empty string, or a string consisting entirely of quote marks, but `""` handles empty strings adequately, and escaping can help with quote marks. (An alternative would be to remove the abutting rule and permit `""""""` to mean "empty string", but abutting quotes seem more useful than long-delimiter empty strings.)
> 
> I agree that there is a need to support alternative delimiters, but subjectively, I find this to be pretty ugly.  It is also a really unfortunate degenerate case for “I just want a large blob of XML” because you’d end up using “"” almost all the time, and you have to use it on every line.

On the other hand, the `"""` does form a much larger, more obvious continuation indicator. It is *extremely* obvious that the above line is not Swift code, but something else embedded in it. It's also extremely obvious what its extent is: when you stop seeing `"""`, you're back to normal Swift code.

I *really* don't like the idea of our only alternatives being "one double-quote mark with backslashing" or "use an entire heredoc". Heredocs have their place, but they are a *very* heavyweight quoting mechanism, and relatively short strings with many double-quotes are pretty common. (Consider, for instance, strings containing unparsed JSON.) I think we need *some* alternative to double-quotes, either single-quotes (with the same semantics, just as an alternative) or this kind of quote-stacking.

> For cases like this, I think it would be reasonable to have a “heredoc” like scheme, which does not allow leading indentation, and does work with all the same modifier characters above.  I do not have a preference on a particular syntax, and haven’t given it any thought, but this would allow you to do things like:
> 
> 	let str = <<EOF
> <?xml version="1.0"?>
> <catalog>
> \t<book id="bk101" empty="">
> \t\t<author>\(author)</author>
> \t</book>
> </catalog>
> EOF
> 
> for example.  You could then turn off escaping and other knobs using the modifier character (somehow, it would have to be incorporated into the syntax of course).

There are two questions and a suggestion I have whenever heredoc syntax comes up.

Q1: Does the heredoc begin immediately, at the next line, or at the next valid place for a statement to start? Heredocs traditionally take the second approach.

Q2: Do you permit heredocs to stack—that is, for a single line to specify multiple heredocs?

S: During the Perl 6 redesign, they decided to use the delimiter's indentation to determine the base indentation for the heredoc:

	func x() -> String {
		return <<EOF
		<?xml version="1.0"?>
		<catalog>
		\t<book id="bk101" empty="">
		\t\t<author>\(author)</author>
		\t</book>
		</catalog>
		EOF
	}

Does that seem like a good approach?

> I generally agree with your down thread remarks about how Swift doesn’t like to have multiple different solutions for the same problem.  OTOH, you could look at “” syntax as being analogous to closure exprs, and heredoc syntax as being analogous to nested functions :-)

Function declarations vs. closure variable assignments were actually the only example I could think of where Swift offers two hugely different ways to write the same thing. I ultimately decided that closure syntax is an inline shorthand for function syntax, and the fact that a declared function is kind of like a declared variable of function type is a red herring. :^)

-- 
Brent Royal-Gordon
Architechies



More information about the swift-evolution mailing list