<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="">On May 1, 2018, at 2:19 PM, Guy Steele <<a href="mailto:guy.steele@oracle.com" class="">guy.steele@oracle.com</a>> wrote:<br class=""><div><blockquote type="cite" class=""><br class="Apple-interchange-newline"><div class=""><span style="font-family: Helvetica; font-size: 16px; 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; float: none; display: inline !important;" class="">the convention that if the last line consists entirely of whitespace and does not</span></div></blockquote><blockquote type="cite" class=""><div class=""><span style="font-family: Helvetica; font-size: 16px; 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; float: none; display: inline !important;" class="">end in a newline, then it should be stripped  _and furthermore the exact same</span></div></blockquote><blockquote type="cite" class=""><div class=""><span style="font-family: Helvetica; font-size: 16px; 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; float: none; display: inline !important;" class="">amount of whitespace should be stripped from all other lines in the literal_</span></div></blockquote></div><br class=""><div class="">Seconded.  (And see discussion of case y in my earlier note to amber-dev,</div><div class="">where the final line is the control line.  Relevant part copied below.)</div><div class=""><br class=""></div><div class="">I keep coming back to the idea that the final line of the quote is the</div><div class="">best place to control indentation stripping.</div><div class=""><br class=""></div><div class="">Here's a rule we could make:  If the trailing line of the literal is blank</div><div class="">(except for indentation) then it is treated as part of the payload delimiter.</div><div class="">In that case, that whitespace must be uniformly present as leading</div><div class="">indentation on all other lines, which is also stripped from every line</div><div class="">of the quote body.  The leading newline (if any) is also stripped.</div><div class=""><br class=""></div><div class=""><div class="">   String y = `<br class="">..___line one<br class="">..line fifty-two<br class="">..___line ninety-nine<br class="">::`;<br class=""></div><div class=""><br class=""></div><div class=""><div class="">The payload starts with "___line one" and ends with "___line ninety-nine".</div></div><div class=""><br class=""></div><div class="">(Here underbar _ is a non-stripped space and colon : is the controlling</div><div class="">stripped space, while period are the non-controlling copies of the stripped</div><div class="">space.)</div></div><div class=""><br class=""></div><div class="">By declaring that the final line gets stripped, the literal's payload</div><div class="">is fully and exactly contained in the displayed source code lines between</div><div class="">the two stripped lines of the literal.  That is not possible unless the last</div><div class="">line is stripped as well as the first.</div><div class=""><br class=""></div><div class=""><div class="">More:  *We can specify that it is an error if the identical leading</div></div><div class="">whitespace is not present on every payload line and also the stripped</div><div class="">trailing line.*  This means there are no invisible surprises:  What you</div><div class="">see at the end of the string is the same as everywhere else.  Previous</div><div class="">versions of the stripping rule distribute the responsibility across all</div><div class="">the lines, but make it difficult or impossible to find the line with the</div><div class="">shortest indent, since (a) it might be in the middle of the literal,</div><div class="">or (b) it might even display the same as other lines with a different</div><div class="">combination of spaces and tabs.  By contrast, making the trailing</div><div class="">line uniquely responsible for controlling the stripping removes</div><div class="">situation (a) and requiring other lines to have the same leading</div><div class="">space substantially removes situation (b).</div><div class=""><br class=""></div><div class=""><div class="">   String y_err = `<br class="">..___line one<br class="">_line fifty-two<br class="">..___line ninety-nine<br class="">::`;  // error:  unaligned indent before "line fifty-two"</div><div class=""><br class=""></div><div class="">I think we should do this.  It would make it a little (a *very* little)</div><div class="">harder to correctly write indented </div><div class=""><br class=""></div></div><div class="">What if the trailing line has non-space characters?  Fine; don't</div><div class="">exdent that literal (that's option A).  Or (option B) exdent by all</div><div class="">the leading whitespace characters, and tack on the remaining</div><div class="">part of the final line to the payload; that gives a hook for ending</div><div class="">a multi-line literal without a newline but keeping the indent feature.</div><div class="">(We have to favor one and disfavor the other, among the two</div><div class="">options of trailing newline and non-trailing newline.)  There's</div><div class="">a third choice (option E) to reserve that condition for future use.</div><div class=""><br class=""></div><div class="">FWIW I like option A as the simplest back-off from fancy stuff:</div><div class=""><br class=""></div><div class=""><div class="">   String y_A = `<br class="">_____line one<br class="">__line fifty-two<br class="">_____line ninety-nine<br class="">__line 100`;  // => really raw no indent stripping<br class=""></div></div><div class=""><br class=""></div><div class="">Rationale:  The trailing line controls exdenting, but *only if*</div><div class="">it is all whitespace:  All the exdent and nothing else.</div><div class=""><br class=""></div><div class="">What about the leading line?  Should it have its indent stripped?</div><div class="">No, because that doesn't help make clean indented rectangles of</div><div class="">source code; stripping that space would be pure puzzler with no upside.</div><div class=""><br class=""></div><div class="">In fact, any non-empty first line is *not* going to align with the rest of</div><div class="">the lines, if indentation is in play.  Therefore, we have similar options</div><div class="">as dealing with non-blanks in the trailing line:  Option A1 is to turn off</div><div class="">exdenting altogether if the first line is non-empty (that's S. Colebourne's</div><div class="">proposal too I think).  Option B1 is keep the first line as-is, even though</div><div class="">it won't align with the rest of the rectangle, and exdent the rest.</div><div class="">Option E1 is to disallow a non-empty leading line.  For completeness,</div><div class="">option E1A is to disallow a leading line *if it begins with whitespace*,</div><div class="">but if it begins with non-whitespace turn off exdenting.  (Note that</div><div class="">under these rules if the trailing line begins with non-whitespace</div><div class="">exdenting is also turned off.)</div><div class=""><br class=""></div><div class="">I think B1 is bad:  It breaks up the rectangle.  I'd like to say that we</div><div class="">don't ever break up rectangles; if a proper text rectangle can't be</div><div class="">formed in the source code, then exdenting is turned off.  No partial</div><div class="">exdents.  I guess A1 is consistent with the previous A, but so is E1A.</div><div class=""><br class=""></div><div class="">   String y_E1A = `__spacey</div><div class=""><div class=""><div class="">..___line one<br class="">..line fifty-two<br class="">..___line ninety-nine<br class="">::line 100`;  // => error: unaligned indent before "spacey"</div></div></div><div class=""><br class=""></div><div class="">Bottom line suggestions:</div><div class=""><br class=""></div><div class="">1. Control indent/exdent string by defining it precisely as the *trailing* line.</div><div class="">2. Omit that trailing line (if it is all-blank), because it is pure control, not payload.</div><div class="">3. If the trailing line has non-blanks, it's not indent control so don't strip or omit anything.</div><div class="">   (B: Or split such a trailing line into leading blanks for indent control and payload.)</div><div class="">4. If stripping, require that *every* payload line without exception have the same prefix.</div><div class="">5. If the leading line is not empty, don't strip anything.  (Rectangles wouldn't align anyway.)</div><div class="">6. Conversely, if stripping, omit the leading line:  It can't contribute anything to a rectangle.</div><div class="">7. Make some edge conditions errors (as in 4) and others "do not strip" cases (as in 3, 5).</div><div class=""><br class=""></div><div class="">Net model is you are either raw-means-raw or raw-is-a-rectangle.  The latter mode</div><div class="">is the only way lines are omitted or left-indents are stripped.  To get into the latter</div><div class="">mode, you have to have a well-formed rectangle with no oddities.  If there's an oddity,</div><div class="">you get an error (if it would be hard to read) or you back off to raw-means-raw.</div><div class="">A multi-line string that doesn't have a leading newline is raw-means-raw, no exceptions.</div><div class=""><br class=""></div><div class="">One downside to putting all the weight on the trailing line:  You don't get all of</div><div class="">Kevin's style choices.  You have to indent the trailing quote the amount you expect</div><div class="">to have stripped.  But on balance this is IMO a feature not a bug:  The exdent</div><div class="">level is defined in one unique place.</div><div class=""><br class=""></div><div class="">— John</div><div class=""><br class=""></div><div class="">P.S. And for the record, here's my errant message to amber-dev:</div><div class=""><br class=""></div><div class=""><div style="margin: 0px;" class=""><span style="font-family: -webkit-system-font, 'Helvetica Neue', Helvetica, sans-serif;" class=""><b class="">From: </b></span><span style="font-family: -webkit-system-font, 'Helvetica Neue', Helvetica, sans-serif;" class="">John Rose <<a href="mailto:john.r.rose@oracle.com" class="">john.r.rose@oracle.com</a>><br class=""></span></div><div style="margin: 0px;" class=""><span style="font-family: -webkit-system-font, 'Helvetica Neue', Helvetica, sans-serif;" class=""><b class="">Subject: </b></span><span style="font-family: -webkit-system-font, 'Helvetica Neue', Helvetica, sans-serif;" class=""><b class="">Re: Raw String Literals (RSL) - indent stripping of multi-line strings</b><br class=""></span></div><div style="margin: 0px;" class=""><span style="font-family: -webkit-system-font, 'Helvetica Neue', Helvetica, sans-serif;" class=""><b class="">Date: </b></span><span style="font-family: -webkit-system-font, 'Helvetica Neue', Helvetica, sans-serif;" class="">April 23, 2018 at 12:20:02 PM PDT<br class=""></span></div><div style="margin: 0px;" class=""><span style="font-family: -webkit-system-font, 'Helvetica Neue', Helvetica, sans-serif;" class=""><b class="">To: </b></span><span style="font-family: -webkit-system-font, 'Helvetica Neue', Helvetica, sans-serif;" class="">Jim Laskey <<a href="mailto:james.laskey@oracle.com" class="">james.laskey@oracle.com</a>><br class=""></span></div><div style="margin: 0px;" class=""><span style="font-family: -webkit-system-font, 'Helvetica Neue', Helvetica, sans-serif;" class=""><b class="">Cc: </b></span><span style="font-family: -webkit-system-font, 'Helvetica Neue', Helvetica, sans-serif;" class="">amber-dev <<a href="mailto:amber-dev@openjdk.java.net" class="">amber-dev@openjdk.java.net</a>><br class=""></span></div><br class=""><div class=""><div class=""><blockquote type="cite" class=""><div class=""><span class="" style="float: none; display: inline !important;"><br class="Apple-interchange-newline">   - Should trailing whitespace be stripped?</span><br class=""></div></blockquote><div class=""><br class=""></div><div class="">As with the "all-indented" case above, trailing space should be</div><div class="">stripped only if there is a way to opt out of stripping.  I think the</div><div class="">trimMarkers API is the way to cover this use case, since it is</div><div class="">rather specialized.</div><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><span class="" style="float: none; display: inline !important;">   - Should the first or last line be removed if blank?</span></div></blockquote><br class=""></div><div class="">Yes.  In essence, the syntax of a quote sequence includes</div><div class="">a line terminator.  This BTW allows non-periodic quote sequences,</div><div class="">which as a corollary allows leading and trailing quote sequences</div><div class="">to be encoded in the RSL:</div><div class=""><br class=""></div><div class="">var hasLeadingAndTrailingTick = ``</div><div class="">   `I went for a walk in the tall brush and picked up some riders.`</div><div class="">   ``;</div><br class=""><div class="">Also, the removal of leading and trailing blank lines gives users</div><div class="">some degrees of stylistic freedom that seem to be customary,</div><div class="">along with the indent-stripping.</div><div class=""><br class=""></div><div class="">Here's a new point along these lines, if I may be so bold:</div><div class=""><br class=""></div><div class="">If we are sticking in non-payload stylistic inputs into RSLs,</div><div class="">we should consider opening up a reservation for future use,</div><div class="">in the form of RSL configurations which are declared to be</div><div class="">illegal.  We could declare that some obviously pathological</div><div class="">subset of near-misses to an indent-stripped RSLs is illegal,</div><div class="">and reserved for future extension.</div><div class=""><br class=""></div><div class="">On the other hand, we are trying very hard to accept every</div><div class="">RSL the user could randomly type in, which is incompatible</div><div class="">with reserving a set of constructs for future use.  This isn't</div><div class="">logically necessary in the style-control use cases; we</div><div class="">can simply declare that some style-control is just illegal,</div><div class="">if we think there's a chance of using that coding space</div><div class="">in the future.</div><div class=""><br class=""></div><div class="">By obviously pathological I mean something like one or</div><div class="">all of these:</div><div class=""><br class=""></div><div class="">   String x = `_<br class="">..line one<br class="">..line two<br class="">..`;<br class=""></div><div class=""><br class=""></div><div class="">   String y = `<br class="">..___line one<br class="">..line fifty-two<br class="">..___line ninety-nine<br class="">..`;<br class=""></div><div class=""><br class=""></div><div class="">   String z = `<br class="">..line one<br class="">..line two<br class="">..___`;<br class=""></div><div class=""><br class=""></div><div class="">(Here underbar _ is a non-stripped space.)</div><div class=""><br class=""></div><div class="">In case x, the is a whitespace on the non-determining blank first line.</div><div class="">Surprisingly, this space doesn't get stripped (under the proposed rules).</div><div class=""><br class=""></div><div class="">In case y, line 52 determines the indent to strip, and this is true even</div><div class="">if it is buried in the middle of 100 lines.  Luckily, in this case, the determining</div><div class="">last line (just before the close-quote) ratifies this choice, so there is a</div><div class="">unique place to look for the stripped indent, without searching the whole string.</div><div class=""><br class=""></div><div class="">In case z, the stripped last line, while a determining line, has extra</div><div class="">whitespace.  This is easy to miss.</div><div class=""><br class=""></div><div class="">I suggest placing a structural constraint on stripped indents, that the</div><div class="">last line, if blank, is stripped, and if stripped, must be of length exactly</div><div class="">zero after the leading indent is trimmed.  That would rule out z and</div><div class="">ameliorate y.</div><div class=""><br class=""></div><div class="">I also suggest ruling out x by requiring that the first line, which is</div><div class="">non-determining, must not have leading whitespace at all.</div><div class="">This doesn't break any of your examples a-f.</div><div class=""><br class=""></div><div class="">Removing cases x and z might remove a class of puzzler about the</div><div class="">significance of leading white spaces near the ends of RSLs.</div><div class="">(Can anyone see a positive use case for them that can't be easily</div><div class="">adjusted to a less pathological form?)</div><div class=""><br class=""></div><div class="">And (getting back to extensions) ruling out x also gives us a tidy</div><div class="">little subspace of RSLs to reserve for future use.  In other words,</div><div class="">an RSL with multiple lines whose leading line begins with a space</div><div class="">can be defined, in future iterations of this feature, to include</div><div class="">envelope information about the RLS, after that space.</div><div class="">Something like this:</div><div class=""><br class=""></div><div class=""><div class="">   String q = `_{cool RSL header invented by our successors}</div><div class="">..line one<br class="">..line two<br class="">..`;<br class=""></div></div><div class=""><br class=""></div><div class="">This envelope information would *not* be included in the payload,</div><div class="">but would be stripped as if the leading line were purely blank.</div><div class="">It would somehow control the processing of the RSL payload,</div><div class="">and/or the parsing of the rest of the RSL.</div><div class=""><br class=""></div><div class="">So in this future feature, the first line would still not be a determining</div><div class="">line, and would be stripped completely, and the stuff between</div><div class="">braces would be used in some way we can't define at present.</div><div class=""><br class=""></div><div class="">I suppose it could have to do with processing embedded escapes.</div><div class=""><br class=""></div><div class=""><div class=""><div class="">   String r = `_{cool RSL header invented by our successors}</div><div class="">..line one<br class="">..line two {cool embedded stuff enabled by RSL header}<br class="">..`;<br class=""></div></div><div class=""><br class=""></div></div><div class=""><div class="">But there's no way to say at this moment what such a future syntax</div><div class="">would look like, and that's my point:  For now we can reserve a corner</div><div class="">of the RSL encoding space for futures.</div></div><div class=""><br class=""></div><div class="">We might never exercise the option, but it seems wise to buy the</div><div class="">option, if it can be bought cheaply as a side effect of restrictions</div><div class="">on pathological indent management.</div><div class=""><br class=""></div><div class="">I didn't raise this earlier though it was on my mind, but as you see</div><div class="">the complexity trade-offs change with built-in indent stripping.</div><div class="">And, obviously, there are other ways to extend RSLs in the future</div><div class="">which may seem better, such as by adding prefixes before the string</div><div class="">quote.  If we don't put constraints on cases x and z above, we still</div><div class="">have options for future extension.</div><div class=""><br class=""></div><div class="">Conversely, even if we are sure we want to make other choices</div><div class="">regarding futures, I think it is a safe move to exclude x and z above.</div><div class=""><br class=""></div><div class="">— John</div></div></div><div class=""><br class=""></div></body></html>