<html><head><style>
body {
        font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
        padding:1em;
        margin:auto;
        background:#fefefe;
}
h1, h2, h3, h4, h5, h6 {
        font-weight: bold;
}
h1 {
        color: #000000;
        font-size: 28pt;
}
h2 {
        border-bottom: 1px solid #CCCCCC;
        color: #000000;
        font-size: 24px;
}
h3 {
        font-size: 18px;
}
h4 {
        font-size: 16px;
}
h5 {
        font-size: 14px;
}
h6 {
        color: #777777;
        background-color: inherit;
        font-size: 14px;
}
hr {
        height: 0.2em;
        border: 0;
        color: #CCCCCC;
        background-color: #CCCCCC;
display: inherit;
}
p, blockquote, ul, ol, dl, li, table, pre {
        margin: 15px 0;
}
a, a:visited {
        color: #4183C4;
        background-color: inherit;
        text-decoration: none;
}
#message {
        border-radius: 6px;
        border: 1px solid #ccc;
        display:block;
        width:100%;
        height:60px;
        margin:6px 0px;
}
button, #ws {
        font-size: 12 pt;
        padding: 4px 6px;
        border-radius: 5px;
        border: 1px solid #bbb;
        background-color: #eee;
}
code, pre, #ws, #message {
        font-family: Monaco;
        font-size: 10pt;
        border-radius: 3px;
        background-color: #F8F8F8;
        color: inherit;
}
code {
        border: 1px solid #EAEAEA;
        margin: 0 2px;
        padding: 0 5px;
}
pre {
        border: 1px solid #CCCCCC;
        overflow: auto;
        padding: 4px 8px;
}
pre > code {
        border: 0;
        margin: 0;
        padding: 0;
}
#ws { background-color: #f8f8f8; }
.bloop_markdown table {
border-collapse: collapse;
font-family: Helvetica, arial, freesans, clean, sans-serif;
color: rgb(51, 51, 51);
font-size: 15px; line-height: 25px;
padding: 0; }
.bloop_markdown table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0; }
.bloop_markdown table tr:nth-child(2n) {
background-color: #f8f8f8; }
.bloop_markdown table tr th {
font-weight: bold;
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
.bloop_markdown table tr td {
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
.bloop_markdown table tr th :first-child, table tr td :first-child {
margin-top: 0; }
.bloop_markdown table tr th :last-child, table tr td :last-child {
margin-bottom: 0; }
.bloop_markdown blockquote{
border-left: 4px solid #dddddd;
padding: 0 15px;
color: #777777; }
blockquote > :first-child {
margin-top: 0; }
blockquote > :last-child {
margin-bottom: 0; }
code, pre, #ws, #message {
word-break: normal;
word-wrap: normal;
}
hr {
display: inherit;
}
.bloop_markdown :first-child {
-webkit-margin-before: 0;
}
code, pre, #ws, #message {
font-family: Menlo, Consolas, Liberation Mono, Courier, monospace;
}
.send { color:#77bb77; }
.server { color:#7799bb; }
.error { color:#AA0000; }</style></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="bloop_markdown"><p>Great explanation thank you Brent. I’m convinced about the closing delimiter now. =)</p>
<hr>
<p>If I understood correctly what Xiaodi Wu meant in his reply, then we could simplify the whole multi-line string literal and also remove the need of disabling the stripping algorithm.</p>
<p>We should ban these examples completely:</p>
<p><code>"""Hello·world!"""</code></p>
<pre><code>"""Hello↵
world!"""
</code></pre>
<pre><code>"""Hello↵
world!↵
"""
</code></pre>
<pre><code>"""↵
Hello↵
world!"""
</code></pre>
<p>Instead an empty multi-line string literal would look like this:</p>
<pre><code>"""↵
"""
</code></pre>
<p>To fix the above example you’d need to write it like this:</p>
<pre><code>"""↵
Hello·world!\↵
"""
</code></pre>
<pre><code>"""↵
Hello↵
world!\↵
"""
</code></pre>
<ul>
<li>Each line in between the delimiters would add implicit new lines if not disabled by a backslash.</li>
<li>The trailing precision is also handled by the backslash.</li>
<li>The indent is handled by the closing delimiter.</li>
<li>It’s easier to learn/teach.</li>
<li>It’s easier to read, because most of the time the line where the starting delimiter is, is filled with some other code.</li>
</ul>
<pre><code>let myString = """↵
⇥ ⇥ Hello↵
⇥ ⇥ world!\↵
⇥ ⇥ """
</code></pre>
<p>Now that would be a true multi-line string literal which needs at least two lines of code. If you’d need a single line literal, <code>""</code> is the obvious pick.</p>
<p></p></div><div class="bloop_original_html"><style>body{font-family:Helvetica,Arial;font-size:13px}</style><div id="bloop_customfont" style="font-family:Helvetica,Arial;font-size:13px; color: rgba(0,0,0,1.0); margin: 0px; line-height: auto;"><br></div> <br> <div id="bloop_sign_1491983543994816000" class="bloop_sign"><div style="font-family:helvetica,arial;font-size:13px">-- <br>Adrian Zubarev<br>Sent with Airmail</div></div> <br><p class="airmail_on">Am 12. April 2017 um 02:32:33, Brent Royal-Gordon (<a href="mailto:brent@architechies.com">brent@architechies.com</a>) schrieb:</p> <blockquote type="cite" class="clean_bq"><span><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div></div><div>
<title></title>
<br class="">
<div>
<blockquote type="cite" class="">
<div class="">On Apr 11, 2017, at 8:08 AM, Adrian Zubarev via
swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div>
<br class="Apple-interchange-newline">
<div class="">
<div class="bloop_markdown" style="font-family: Helvetica, Arial; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254);">
<p style="margin: 15px 0px; -webkit-margin-before: 0px;" class="">
That’s also the example that kept me thinking for a while.</p>
<hr style="height: 0.2em; border: 0px; color: rgb(204, 204, 204); background-color: rgb(204, 204, 204); display: inherit;" class="">
<p style="margin: 15px 0px;" class="">Overall the proposal is a
great compromise to some issues I had with the first version.
However I have a few more questions:</p>
<ul style="margin: 15px 0px;" class="">
<li style="margin: 15px 0px; -webkit-margin-before: 0px;" class="">
Why can’t we make it consistent and let the compiler add a new line
after the starting delimiter.</li>
</ul>
<pre style="margin: 15px 0px; font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(204, 204, 204); overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;" class=""><code class="swift" style="font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 0px; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;">
let string = """↵
Swift↵
"""
// result
↵Swift↵
</code></pre>
<p style="margin: 15px 0px;" class="">If one would would the
behavior from the proposal it’s really easy to add a backslash
after the starting delimiter.</p>
<pre style="margin: 15px 0px; font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(204, 204, 204); overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;" class=""><code class="swift" style="font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 0px; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;">
let string = """\↵
Swift\↵
"""
// result
Swift
</code></pre>
<p style="margin: 15px 0px;" class="">This would be consistent and
less confusing to learn.</p>
</div>
</div>
</blockquote>
That would mean that code like this:</div>
<div><br class=""></div>
<div>print("""</div>
<div>A whole bunch of </div>
<div>multiline text</div>
<div>""")</div>
<div>
<div>print("""</div>
<div>A whole bunch more </div>
<div>multiline text</div>
<div>""")</div>
<div><br class=""></div>
<div>Will print (with - to indicate blank lines):</div>
<div><br class=""></div>
<div>-</div>
<div>A whole bunch of</div>
<div>multiline text</div>
<div>-</div>
<div>-</div>
<div>A whole bunch more</div>
<div>multiline text</div>
<div>-</div>
<div><br class=""></div>
<div>This is, to a first approximation, never what you actually
want the computer to do.</div>
<blockquote type="cite" class="">
<div class="">
<div class="bloop_markdown" style="font-family: Helvetica, Arial; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254);">
<ul style="margin: 15px 0px;" class="">
<li style="margin: 15px 0px; -webkit-margin-before: 0px;" class="">
Can’t we make the indent algorithm work like this instead?</li>
</ul>
<pre style="margin: 15px 0px; font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(204, 204, 204); overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;" class=""><code style="font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 0px; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;" class="">let string = """\↵
····<tag>↵
······content text↵
····</tag>""" // Indent starts with the first non space character
// result
<tag>↵
··content text↵
</tag>
</code></pre>
<p style="margin: 15px 0px;" class="">The line where the closing
delimiter is trims all space chapters and the indent for the whole
multi-line string is starting at the point where the first
non-space chapters is in that line.</p>
</div>
</div>
</blockquote>
<div>We could; I discuss that briefly in the very last section, on
alternatives to the indentation stripping we specify:</div>
<div><br class=""></div>
<div>
<div class="">• Stripping indentation to match the depth of the
least indented line: Instead of removing indentation to match
the end delimiter, you remove indentation to match the least
indented line of the string itself. The issue here is that, if
all lines in a string should be indented, you can't use
indentation stripping. Ruby 2.3 does this with its heredocs,
and Python's dedent function also implements this
behavior.<br class="">
<br class=""></div>
That doesn't quite capture the entire breadth of the problem with
this algorithm, though. What you'd like to do is say, "all of these
lines are indented four columns, so we should remove four columns
of indentation from each line". But you don't have columns; you
have tabs and spaces, and they're incomparable because the compiler
can't know what tab stops you set. So we'd end up calculating a
common prefix of whitespace for all lines and removing that. But
that means, when someone mixes tabs and spaces accidentally, you
end up stripping an amount of indentation that is unrelated to
anything visible in your code. We could perhaps emit a warning in
some suspicious circumstances (like "every line has whitespace just
past the end of indentation, but some use tabs and others use
spaces"), but if we do, we can't know which one is supposed to be
correct. With the proposed design, we know what's correct—the last
line—and any deviation from it can be flagged *at the particular
line which doesn't match our expectation*.</div>
<div><br class=""></div>
<div>Even without the tabs and spaces issue, consider the case
where you accidentally don't indent a line far enough. With your
algorithm, that's indistinguishable from wanting the other lines to
be indented more than that one, so we generate a result you don't
want and we don't (can't!) emit a warning to point out the mistake.
With the proposed algorithm, we can notice there's an error and
point to the line at fault.</div>
<div><br class=""></div>
<div>Having the closing delimiter always be on its own line and
using it to decide how much whitespace to strip is better because
it gives the compiler a firm baseline to work from. That means it
can tell you what's wrong and where, instead of doing the dumb
computer thing and computing a result that's technically correct
but useless.</div>
<blockquote type="cite" class="">
<div class="">
<div class="bloop_markdown" style="font-family: Helvetica, Arial; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254);">
<p style="margin: 15px 0px;" class="">PS: If we’d get this feature
in Swift, it would be nice if Xcode and other IDEs which supports
Swift could show space characters that are inside a string literal
(not other space character <- which is already supported), so it
would be easier to tell what’s part of the string and what is
not.</p>
</div>
</div>
</blockquote>
That would be very nice indeed. The prototype's tokenizer simply
concatenates together and computes the string literal's contents
after whitespace stripping, but in principle, I think it could
probably preserve enough information to tell SourceKit where the
indentation ends and the literal content begins. (The prototype is
John's department, though, not mine.) Xcode would then have to do
something with that information, though, and swift-evolution can't
make the Xcode team do so. But I'd love to see a faint reddish
background behind tripled string literal content or a vertical line
at the indentation boundary.</div>
<div><br class=""></div>
<div>In the meantime, this design *does* provide an unambiguous
indicator of how much whitespace will be trimmed: however much is
to the left of the closing delimiter. You just have to imagine the
line extending upwards from there. I think that's an important
thing to have.</div>
<br class="">
<div class="">
<div class="">
<div style="font-size: 12px;" class=""><span class="Apple-style-span" style="border-collapse: separate; font-variant-ligatures: normal; font-variant-east-asian: normal; font-variant-position: normal; line-height: normal; border-spacing: 0px;">
-- </span></div>
<div style="font-size: 12px;" class=""><span class="Apple-style-span" style="border-collapse: separate; font-variant-ligatures: normal; font-variant-east-asian: normal; font-variant-position: normal; line-height: normal; border-spacing: 0px;">
Brent Royal-Gordon</span></div>
<div style="font-size: 12px;" class=""><span class="Apple-style-span" style="border-collapse: separate; font-variant-ligatures: normal; font-variant-east-asian: normal; font-variant-position: normal; line-height: normal; border-spacing: 0px;">
Architechies</span></div>
</div>
</div>
<br class="">
</div></div></span></blockquote></div><div class="bloop_markdown"><p></p></div></body></html>