[swift-evolution] multi-line string literals.
John Siracusa
siracusa at gmail.com
Wed Apr 27 11:35:23 CDT 2016
On Wed, Apr 27, 2016 at 9:08 AM, Vladimir.S via swift-evolution <
swift-evolution at swift.org> wrote:
>
> I expect to be able to have multiline text exactly *"as-is"* in my source
> file. No escaping, no interpolation, etc. I believe this should be a target
> of the proposal.
>
I also see this as one of the most important goals of any multi-line
string-handling proposal. The "no escapes required" syntax doesn't have to
be the only way to handle multi-line strings, but it should be one of the
available ways.
-John
P.S. - Secondarily (and broader than just multi-line strings) I think there
should also be a way to avoid backslash-itis in strings of all kinds by
providing some flexibility in string delimiters. But that's for another
thread…
> Otherwise, I reject to see any reason to introduce anything new at this
> area - we already can concatenate strings and place them on next line and
> escape special characters.
>
> In your proposal, you have to escape characters in your text, you need to
> carefully modify the copy-pasted text to be allowed as correct multi-line
> string. Also, what if I need to have spaces *at the end of string* ? Editor
> can just trimmed them, and we can't clearly see them.
>
> Personally I need to be able to have this(in some way) in my code:
> (note this "\tuttorial" and "\(edition" - this is just text, I want to
> have inside my xml)
>
> let xml = ... // some marker to start the multi-line str
> <?xml version="1.0"?>
> <catalog>
> <book id="myid" empty="">
> <author>myAuthor</author>
> <title>myTitle \tutorial 1\(edition 2)</title>
> </book>
> </catalog>
> ... // some marker here to stop multi-line str
>
> It seems like we need some markers for end-of-the-line to be able to keep
> spaces/tabs in the end of line.
>
> What about something like this. Two suported variants : first when we need
> to keep spaces in the end of line, and second when we don't need
> spaced(will be trimmed by parser)
>
> #1 (parser should just take the text between first and last quote *as-is*)
>
> let xml = "\
> "<?xml version="1.0"?> " // yes, *I need* these spaces at the end
> "<catalog>"
> " <book id="myid" empty="">"
> " <author>myAuthor</author>"
> " <title>myTitle \tutorial 1\(edition 2)</title>"
> " </book>"
> "</catalog>"
> "
>
> #2 in this case we don't need any spaces/tabs in the end of lines(don't
> care):
> (parser takes all that is after | as-is but trims any trailing spaces/tabs
> in lines to be clear in behaviour)
>
> let xml = "\
> |<?xml version="1.0"?>
> |<catalog>
> | <book id="myid" empty="">
> | <author>myAuthor</author>
> | <title>myTitle \tutorial 1\(edition 2)</title>
> | </book>
> |</catalog>
> "
>
> Or these two could be combined in one(as-is between |..|) but I'm not sure:
>
> let xml = "\
> |<?xml version="1.0"?> | // yes, I need these spaces
> |<catalog>| // we have to have closing symbol in this case in other lines
> | <book id="myid" empty="">|
> | <author>myAuthor</author>|
> | <title>myTitle \tutorial 1\(edition 2)</title>|
> | </book>|
> |</catalog>|
> "
>
>
>
>> Gist: <https://gist.github.com/brentdax/c580bae68990b160645c030b2d0d1a8f>
>>
>>
>> Multiline string literals
>>
>> * Proposal: SE-NNNN
>> <
>> https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md
>> >
>> * Author(s): Brent Royal-Gordon <https://github.com/brentdax>
>> * Status: First Draft
>> * Review manager: TBD
>>
>>
>> <
>> https://gist.github.com/brentdax/c580bae68990b160645c030b2d0d1a8f#introduction
>> >Introduction
>>
>> In Swift 2.2, the only means to insert a newline into a string literal is
>> the |\n| escape. String literals specified in this way are generally ugly
>> and unreadable. We propose a multiline string feature inspired by English
>> punctuation which is a straightforward extension of our existing string
>> literals.
>>
>> Swift-evolution thread: multi-line string literals.
>> <
>> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160418/015500.html
>> >
>>
>>
>> <
>> https://gist.github.com/brentdax/c580bae68990b160645c030b2d0d1a8f#draft-notes
>> >Draft
>> Notes
>>
>> *
>>
>> This draft differs from the prototypes being thrown around on the list
>> in that it specifies that comments should be treated as whitespace,
>> and
>> that whitespace-only lines in the middle of a multiline string should
>> be ignored. I'm not sure if this is feasible from a parsing
>> standpoint,
>> and I'd like feedback from implementers on this point.
>>
>> *
>>
>> This draft also specifies diagnostics which should be included.
>> Feedback on whether these are good choices would be welcome.
>>
>> *
>>
>> I am considering allowing you to put a backslash before the newline to
>> indicate it should /not/ be included in the literal. In other words,
>> this code:
>>
>> print("foo\
>> "bar")
>>
>> Would print |"foobar"|. However, I think this should probably be
>> proposed separately, because there may be a better way to do it.
>>
>> *
>>
>> I've listed only myself as an author because I don't want to put
>> anyone
>> else's name to a document they haven't seen, but there are others who
>> deserve to be listed (John Holdsworth at least). Let me know if you
>> think you should be included.
>>
>>
>> <
>> https://gist.github.com/brentdax/c580bae68990b160645c030b2d0d1a8f#motivation
>> >Motivation
>>
>> As Swift begins to move into roles beyond app development, code which
>> needs
>> to generate text becomes a more important use case. Consider, for
>> instance,
>> generating even a small XML string:
>>
>> let xml = "<?xml version=\"1.0\"?>\n<catalog>\n\t<book id=\"bk101\"
>> empty=\"\">\n\t\t<author>\(author)</author>\n\t</book>\n</catalog>"
>>
>> The string is practically unreadable, its structure drowned in escapes and
>> run-together characters; it looks like little more than line noise. We can
>> improve its readability somewhat by concatenating separate strings for
>> each
>> line and using real tabs instead of |\t| escapes:
>>
>> let xml = "<?xml version=\"1.0\"?>\n" +
>> "<catalog>\n" +
>> " <book id=\"bk101\" empty=\"\">\n" +
>> " <author>\(author)</author>\n" +
>> " </book>\n" +
>> "</catalog>"
>>
>> However, this creates a more complex expression for the type checker, and
>> there's still far more punctuation than ought to be necessary. If the most
>> important goal of Swift is making code readable, this kind of code falls
>> far short of that goal.
>>
>>
>> <
>> https://gist.github.com/brentdax/c580bae68990b160645c030b2d0d1a8f#proposed-solution
>> >Proposed
>> solution
>>
>> We propose that, when Swift is parsing a string literal, if it reaches the
>> end of the line without encountering an end quote, it should look at the
>> next line. If it sees a quote mark there (a "continuation quote"), the
>> string literal contains a newline and then continues on that line.
>> Otherwise, the string literal is unterminated and syntactically invalid.
>>
>> Our sample above could thus be written as:
>>
>> let xml = "<?xml version=\"1.0\"?>
>> "<catalog>
>> " <book id=\"bk101\" empty=\"\">
>> " <author>\(author)</author>
>> " </book>
>> "</catalog>"
>>
>> (Note that GitHub is applying incorrect syntax highlighting to this code
>> sample, because it's applying Swift 2 rules.)
>>
>> This format's unbalanced quotes might strike some programmers as strange,
>> but it attempts to mimic the way multiple lines are quoted in English
>> prose. As an English Stack Exchange answer illustrates
>> <http://english.stackexchange.com/a/96613/64636>:
>>
>> “That seems like an odd way to use punctuation,” Tom said. “What harm
>> would there be in using quotation marks at the end of every
>> paragraph?”
>>
>> “Oh, that’s not all that complicated,” J.R. answered. “If you closed
>> quotes at the end of every paragraph, then you would need to
>> reidentify
>> the speaker with every subsequent paragraph.
>>
>> “Say a narrative was describing two or three people engaged in a
>> lengthy conversation. If you closed the quotation marks in the
>> previous
>> paragraph, then a reader wouldn’t be able to easily tell if the
>> previous speaker was extending his point, or if someone else in the
>> room had picked up the conversation. By leaving the previous
>> paragraph’s quote unclosed, the reader knows that the previous speaker
>> is still the one talking.”
>>
>> “Oh, that makes sense. Thanks!”
>>
>> Similarly, omitting the ending quotation mark tells the code's reader (and
>> compiler) that the literal continues on the next line, while including the
>> continuation quote reminds the reader (and compiler) that this line is
>> part
>> of a string literal.
>>
>>
>> <
>> https://gist.github.com/brentdax/c580bae68990b160645c030b2d0d1a8f#benefits-of-continuation-quotes
>> >Benefits
>> of continuation quotes
>>
>> It would be simpler to not require continuation quotes, so why are they
>> required by this proposal? There are three reasons:
>>
>> 1.
>>
>> *They help the compiler pinpoint errors in string literal
>> delimiting.* If continuation quotes were not required, then a missing
>> end quote would be interpreted as a multiline string literal. This
>> string literal would continue until the compiler encountered either
>> another quote mark—perhaps at the site of another string literal or in
>> a comment—or the end of the file. In either case, the compiler could
>> at
>> best only indicate the start of the runaway string literal; in
>> pathological cases (for instance, if the next string literal
>> was |"+"|), it might not even be able to do that properly.
>>
>> With continuation quotes required, if you forget to include an end
>> quote, the compiler can tell that you did not intend to create a
>> multiline string and flag the line that actually has the problem. It
>> can also provide immediately actionable fix-it assistance. The fact
>> that there is a redundant indication on each line of the programmer's
>> intent to include that line in a multiline quote allows the compiler
>> to
>> guess the meaning of the code.
>>
>> 2.
>>
>> *They separate indentation from the string's contents.* Without
>> continuation quotes, there would be no obvious indication of whether
>> whitespace at the start of the line was intended to indent the string
>> literal so it matched the surrounding code, or whether that whitespace
>> was actually meant to be included in the resulting string. Multiline
>> string literals would either have to put subsequent lines against the
>> left margin, or apply error-prone heuristics to try to guess which
>> whitespace was indentation and which was string literal content.
>>
>> 3.
>>
>> *They improve the ability to quickly recognize the literal.* The |"|
>> on
>> each line serves as an immediately obvious indication that the line is
>> part of a string literal, not code, and the row of |"| characters in a
>> well-formatted file allows you to quickly scan up and down the file to
>> see the extent of the literal.
>>
>>
>> <
>> https://gist.github.com/brentdax/c580bae68990b160645c030b2d0d1a8f#detailed-design
>> >Detailed
>> design
>>
>> When Swift is parsing a string literal and reaches the end of a line
>> without finding a closing quote, it examines the next line, applying the
>> following rules:
>>
>> 1.
>>
>> If the next line is all whitespace, it is ignored; Swift moves on to
>> the line afterward, applying these rules again.
>>
>> 2.
>>
>> If the next line begins with whitespace followed by a continuation
>> quote, then the string literal contains a newline followed by the
>> contents of the string literal starting on that line. (This line may
>> itself have no closing quote, in which case the same rules apply to
>> the
>> line which follows.)
>>
>> 3.
>>
>> If the next line contains anything else, Swift raises a syntax error
>> for an unterminated string literal. This syntax error should offer two
>> fix-its: one to close the string literal at the end of the current
>> line, and one to include the next line in the string literal by
>> inserting a continuation quote.
>>
>> Rules 1 and 2 should treat comments as though they are whitespace; this
>> allows you to comment out individual lines in a multiline string literal.
>> (However, commenting out the last line of the string literal will still
>> make it unterminated, so you don't have a completely free hand in
>> commenting.)
>>
>>
>> <
>> https://gist.github.com/brentdax/c580bae68990b160645c030b2d0d1a8f#impact-on-existing-code
>> >Impact
>> on existing code
>>
>> Failing to close a string literal before the end of the line is currently
>> a
>> syntax error, so no valid Swift code should be affected by this change.
>>
>>
>> <
>> https://gist.github.com/brentdax/c580bae68990b160645c030b2d0d1a8f#alternatives-considered
>> >Alternatives
>> considered
>>
>>
>> <
>> https://gist.github.com/brentdax/c580bae68990b160645c030b2d0d1a8f#requiring-no-continuation-character
>> >Requiring
>> no continuation character
>>
>> The main alternative is to not require a continuation quote, and simply
>> extend the string literal from the starting quote to the ending quote,
>> including all newlines between them. For example:
>>
>> let xml = "<?xml version=\"1.0\"?>
>> <catalog>
>> <book id=\"bk101\" empty=\"\">
>> <author>\(author)</author>
>> </book>
>> </catalog>"
>>
>> This has several advantages:
>>
>> 1.
>>
>> It is simpler.
>>
>> 2.
>>
>> It is less offensive to programmers' sensibilities (since there are no
>> unmatched |"| characters).
>>
>> 3.
>>
>> It does not require that you edit the string literal to insert a
>> continuation quote in each line.
>>
>> Balanced against the advantages, however, is the loss of the improved
>> diagnostics, code formatting, and visual affordances mentioned in the
>> "Benefits of continuation quotes" section above.
>>
>> In practice, we believe that editor support (such as "Paste as String
>> Literal" or "Convert to String Literal" commands) can make adding
>> continuation quotes less burdensome, while also providing other
>> conveniences like automatic escaping. We believe the other two factors are
>> outweighed by the benefits of continuation quotes.
>>
>>
>> <
>> https://gist.github.com/brentdax/c580bae68990b160645c030b2d0d1a8f#use-a-different-delimiter-for-multiline-strings
>> >Use
>>
>> a different delimiter for multiline strings
>>
>> The initial suggestion was that multiline strings should use a different
>> delimiter, |"""|, at the beginning and end of the string, with no
>> continuation characters between. This solution was rejected because it has
>> the same issues as the "no continuation character" solution, and because
>> it
>> was mixing two orthogonal issues (multiline strings and alternate
>> delimiters).
>>
>> Another suggestion was to support a heredoc syntax, which would allow you
>> to specify a placeholder string literal on one line whose content begins
>> on
>> the next line, running until some arbitrary delimiter. For instance, if
>> Swift adopted Perl 5's syntax, it might support code like:
>>
>> connection.sendString(<<"END")
>> <?xml version="1.0"?>
>> <catalog>
>> <book id="bk101" empty="">
>> <author>\(author)</author>
>> </book>
>> </catalog>
>> END
>>
>> In addition to the issues with the |"""| syntax, heredocs are complicated
>> both to explain and to parse, and are not a natural extension of Swift's
>> current string syntax.
>>
>> Both of these suggestions address interesting issues with string literals,
>> solving compelling use cases. They're just not that good at fixing the
>> specific issue at hand. We might consider them in the future to address
>> those problems to which they are better suited.
>>
>>
>> <
>> https://gist.github.com/brentdax/c580bae68990b160645c030b2d0d1a8f#fixing-other-string-literal-readability-issues
>> >Fixing
>> other string literal readability issues
>>
>> This proposal is narrowly aimed at multiline strings. It intentionally
>> doesn't tackle several other problems with string literals:
>>
>> *
>>
>> Reducing the amount of double-backslashing needed when working with
>> regular expression libraries, Windows paths, source code generation,
>> and other tasks where backslashes are part of the data.
>>
>> *
>>
>> Alternate delimiters or other strategies for writing strings
>> with |"| characters in them.
>>
>> *
>>
>> String literals consisting of very long pieces of text which are best
>> represented completely verbatim.
>>
>> These are likely to be subjects of future proposals, though not
>> necessarily
>> during Swift 3.
>>
>> This proposal also does not attempt to address regular expression
>> literals.
>> The members of the core team who are interested in regular expression
>> support have ambitions for that feature which put it out of scope for
>> Swift 3.
>>
>> --
>> Brent Royal-Gordon
>> Architechies
>>
>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160427/ff4f7ae0/attachment.html>
More information about the swift-evolution
mailing list