<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div><blockquote type="cite" class=""><div class="">On Apr 12, 2017, at 11:58 AM, Jarod Long via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><div class=""><div class=""><div name="messageBodySection" style="font-size: 14px; font-family: -apple-system, BlinkMacSystemFont, sans-serif;" class=""><div class=""><br class=""></div>
<div class="">On a separate note, I'd like to bring up the de-indentation behavior I described earlier again. I still feel that having the position of the closing delimiter determine how much whitespace is de-indented is not very natural or intuitive, since I don't think there is any precedent in standard Swift styling to indent a closing delimiter to the same level as its content.</div></div></div></div></blockquote><div><br class=""></div><div>String literal delimiters are very different from other delimiters because they switch the parser into a different mode where characters are interpreted in vastly different ways, and every character has a significant meaning. For instance, it's good practice to put either a space, or a newline and indentation, between array and dictionary literal delimiters or curly brackets and their content, but this is not possible with a string literal because the space would count as part of the content. This is the same way: you can't outdent because whitespace is significant inside a string literal, so it would change the meaning.</div><div><br class=""></div><div>I think that this probably seems way weirder on paper than it really is in practice. I recommend that you try it and see how it feels.</div><br class=""><blockquote type="cite" class=""><div class=""><div class=""><div name="messageBodySection" style="font-size: 14px; font-family: -apple-system, BlinkMacSystemFont, sans-serif;" class=""><div class="">Stripping the most common whitespace possible from each line seems to be a much more intuitive and flexible solution in terms of formatting, and it's still compatible with the proposed formatting if that's anyone's preference.</div>
<div class=""></div></div></div></div></blockquote><div><br class=""></div><div>I discuss this at length in the Rationale section for indentation stripping. If you'll forgive me for quoting myself:</div><div><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(36, 41, 46); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);" class="">We could instead use an algorithm where the longest common whitespace prefix is removed from all lines; in well-formed code, that would produce the same behavior as this algorithm. But when <em style="box-sizing: border-box;" class="">not</em> well-formed—when one line was accidentally indented less than the delimiter, or when a user mixed tabs and spaces accidentally—it would lead to valid, but incorrect and undiagnosable, behavior. For instance, if one line used a tab and other lines used spaces, Swift would not strip indentation from any of the lines; if most lines were indented four spaces, but one line was indented three, Swift would strip three spaces of indentation from all lines. And while you would still be able to create a string with all lines indented by indenting the closing delimiter less than the others, many users would never discover this trick.</p></div></div></blockquote><div><div><div class="">Let me provide an example to illustrate what I'm talking about. Suppose you want to say this:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>····xml += """\↵<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>············<book id="bk\(id)">↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>················<author>\(author)</author>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>················<title>\(title)</title>↵<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>················<genre>\(genre)</genre>↵<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>················<price>\(price)</price>↵<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>············</book>↵<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>············"""↵<br class=""><br class=""></div><div class="">But instead, you miss just one little insignificant character:</div><div class=""><br class=""></div><div class=""><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>····xml += """\↵<span style="color: rgb(24, 54, 145); font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; background-color: rgb(246, 248, 250);" class=""><br class=""></span><span class="Apple-tab-span" style="white-space:pre">        </span>···········<book id="bk\(id)">↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>················<author>\(author)</author>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>················<title>\(title)</title>↵<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>················<genre>\(genre)</genre>↵<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>················<price>\(price)</price>↵<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>············</book>↵<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>············"""↵</div></div></div><div><br class=""></div><div>This is the kind of mistake you will almost certainly never notice by hand inspection. You probably can't see the mistake without looking very carefully—and this is with invisible whitespace replaced with visible dots! But in the least-common-whitespace design, it's perfectly valid, and generates this:</div><div><br class=""></div><div><div><div class=""><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span><book id="bk\(id)">↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>·····<author>\(author)</author>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>·····<title>\(title)</title>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>·····<genre>\(genre)</genre>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>·····<price>\(price)</price>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>·</book>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>·</div></div><div class=""><br class=""></div><div class="">That is not what you wanted. I'm pretty sure it's almost *never* what you want. But it's valid, it's going to be accepted, and it's going to affect every single line of the literal in a subtle way. (Plus the next line, thanks to that trailing space!) It's not something we can warn about, either, because it's perfectly valid. To fix it, you'll have to notice it's wrong and then work out why that happened.</div><div class=""><br class=""></div><div class="">In the proposed design, on the other hand, we have a single source of truth for indentation: the last line tells us how much we should remove. That means we can actually call a mistake a mistake. The very same example, run through the proposed algorithm, produces this, plus a warning on the first line:</div><div class=""><br class=""></div><div class=""><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>···········<book id="bk\(id)">↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>····<author>\(author)</author>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>····<title>\(title)</title>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>····<genre>\(genre)</genre>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>····<price>\(price)</price>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span></book>↵</div></div><div class=""><br class=""></div><div class="">Notice that there is only one line that comes out incorrectly, that it's the line which has the mistake, that the mistake is large and noticeable in the output, *and* that we were also able to emit a compile-time warning pointing to the exact line of code that was mistaken. That outcome is night-and-day better.</div><div class=""><br class=""></div><div class="">Now consider mixed tabs and spaces:</div><div class=""><br class=""></div><div class=""><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>····xml += """\↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>············<book id="bk\(id)">↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>················<author>\(author)</author>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>········⇥ ····<title>\(title)</title>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>················<genre>\(genre)</genre>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>················<price>\(price)</price>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>············</book>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>············"""↵</div></div><div class=""><br class=""></div><div class="">(I'm assuming a tab stop of 4, so mentally adjust that example if you need to.)</div><div class=""><br class=""></div><div class="">With your design, the compiler happily removes the common whitespace and writes code which does this:</div><div class=""><br class=""></div><div class=""><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>····<book id="bk\(id)">↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>········<author>\(author)</author>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>⇥ ····<title>\(title)</title>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>········<genre>\(genre)</genre>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>········<price>\(price)</price>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>····</book>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>····</div></div><div class=""><br class=""></div><div class="">Once again, every line is affected—including lines after this snippet, since there are spaces after the last newline. Once again, there can be no warning. You'll need to notice the problem and then figure out what happened.</div><div class=""><br class=""></div><div class="">By contrast, with the proposed design, you get this, plus a warning:</div><div class=""><br class=""></div><div class=""><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span><book id="bk\(id)">↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>····<author>\(author)</author>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>········⇥ ····<title>\(title)</title>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>····<genre>\(genre)</genre>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>····<price>\(price)</price>↵</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span></book>↵</div></div><div class=""><br class=""></div><div class="">Once again, the only line that's affected is the bad line, *and* you get a warning. In this case, I think the warning could probably point you to the exact *character* that causes the problem.</div><div class=""><br class=""></div><div class="">Basically, common-whitespace-prefix makes the compiler act like a dumb computer that does what you say, not what you want. The proposed algorithm makes the compiler act like a smart human that notices when you ask for something that doesn't make sense and tells you about the problem.</div><div class=""><br class=""></div><div class="">(Also note how, if you want a trailing newline, you still end up having the delimiter on a separate line aligned with the other text anyway! Stripping the common whitespace prefix in practice still ends up looking exactly the same as what you object to.)</div><div class=""><br class=""></div></div></div><blockquote type="cite" class=""><div class=""><div class=""><div name="messageBodySection" style="font-size: 14px; font-family: -apple-system, BlinkMacSystemFont, sans-serif;" class=""><div class="">The only functional limitation that I see is that if you can't have leading whitespace in the interpreted string if you actually want that. That doesn't seem like a very important use case to me,</div></div></div></div></blockquote><div><br class=""></div><div>We showed an example of this being done in the Rationale section, and it was a *very* plausible example. I don't think it's rare or unnecessary at all; I think it's a really important use case, particularly for generating pretty-printed code or markup.</div><br class=""><blockquote type="cite" class=""><div class=""><div class=""><div name="messageBodySection" style="font-size: 14px; font-family: -apple-system, BlinkMacSystemFont, sans-serif;" class=""><div class="">but if we think it is important, it could be supported by something like having a backslash in the leading whitespace at the location where it should be preserved from.</div>
<div class=""></div></div></div></div></blockquote><div><br class=""></div><div>There are good reasons not to allow backslashing of several different varieties of whitespace, and people were really unhappy with designs that required them to modify every line of text. I think this is a non-starter.</div><br class=""><blockquote type="cite" class=""><div class=""><div class=""><div name="messageBodySection" style="font-size: 14px; font-family: -apple-system, BlinkMacSystemFont, sans-serif;" class=""><div class="">If we're set on the proposed behavior, have we considered what happens if the closing delimiter goes beyond the non-whitespace content of the string?</div>
<div class=""><br class=""></div>
<div class="">let string = """</div>
<div class=""> aa</div>
<div class=""> bb</div>
<div class=""> cc</div>
<div class=""> """</div>
<div class=""><br class=""></div>
<div class="">Does it strip the non-whitespace characters? Does it strip up to the non-whitespace characters? Does it generate an error?</div>
</div>
</div></div></blockquote><div><br class=""></div><div>It strips nothing and generates a warning on each offending line (but not an error, because whitespace problems are usually minor enough that there's no need to interrupt your debugging to fix some indentation). This was covered in the proposal.</div><div><br class=""></div><div>(In an example like this, where every line is less indented than the delimiter, we might emit a different warning suggesting that the delimiter's indentation is wrong. That's a QoI issue, though, not the kind of thing we need to cover in a proposal.)</div></div><br class=""><div 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;"><div class=""><div style="font-size: 12px; " class="">-- </div><div style="font-size: 12px; " class="">Brent Royal-Gordon</div><div style="font-size: 12px; " class="">Architechies</div></div></span>
</div>
<br class=""></body></html>