From brian.goetz at oracle.com Mon Jun 4 21:54:01 2018 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 4 Jun 2018 17:54:01 -0400 Subject: [constables] RFR of constants API In-Reply-To: <451987dd-9371-552f-908d-e57fdc1f09ff@oracle.com> References: <451987dd-9371-552f-908d-e57fdc1f09ff@oracle.com> Message-ID: <714a3a32-f318-4b46-f8a1-012f8e3cae3e@oracle.com> Robert Field raised the following possible bug in the API of MethodHandleDesc. A Constant_MethodHandle_info has the following contents: ? refKind ? reference to MethodRef or InterfaceMethodRef ? reference to NameAndType Most of these map directly; we extract refKind from Kind, we extract name from name, we extract type descriptor from type. But, it doesn't seem like there's a way to express both (refkind=invokespecial, Constant_MethodRef_info) and (refkind=invokevirtual, Constant_InterfaceMethodRef_info). One of the inputs to a MHDesc is a Kind enum constant.? Currently, they map 1:1 with refKind, but it seems to me we need to differentiate between INTERFACE_VIRTUAL and INTERFACE_SPECIAL, where in the latter case, refKind=special but we use an InterfaceMethodRef? On 4/27/2018 1:31 PM, Vicente Romero wrote: > Hi all, > > Please review the current proposal of the constants API, which are > nominal descriptor types defined in pkg java.lang.invoke.constant. The > code can be found at [1]. This API is being developed in the context > of JEP 303: Intrinsics for the LDC and INVOKEDYNAMIC Instructions [2] > > Thanks in advance for your comments, > Vicente > > [1] http://cr.openjdk.java.net/~vromero/constant.api/webrev.00 > [2] http://openjdk.java.net/jeps/303 From forax at univ-mlv.fr Mon Jun 4 22:23:40 2018 From: forax at univ-mlv.fr (Remi Forax) Date: Tue, 5 Jun 2018 00:23:40 +0200 (CEST) Subject: [constables] RFR of constants API In-Reply-To: <714a3a32-f318-4b46-f8a1-012f8e3cae3e@oracle.com> References: <451987dd-9371-552f-908d-e57fdc1f09ff@oracle.com> <714a3a32-f318-4b46-f8a1-012f8e3cae3e@oracle.com> Message-ID: <1010138570.500415.1528151020521.JavaMail.zimbra@u-pem.fr> Yes, good catch, in ASM we use a supplementary boolean to say if it's a MethodRef or an InterfaceRef. R?mi ----- Mail original ----- > De: "Brian Goetz" > ?: "Vicente Romero" , "amber-spec-experts" > Envoy?: Lundi 4 Juin 2018 23:54:01 > Objet: Re: [constables] RFR of constants API > Robert Field raised the following possible bug in the API of > MethodHandleDesc. > > A Constant_MethodHandle_info has the following contents: > ? refKind > ? reference to MethodRef or InterfaceMethodRef > ? reference to NameAndType > > Most of these map directly; we extract refKind from Kind, we extract > name from name, we extract type descriptor from type. But, it doesn't > seem like there's a way to express both (refkind=invokespecial, > Constant_MethodRef_info) and (refkind=invokevirtual, > Constant_InterfaceMethodRef_info). > > One of the inputs to a MHDesc is a Kind enum constant.? Currently, they > map 1:1 with refKind, but it seems to me we need to differentiate > between INTERFACE_VIRTUAL and INTERFACE_SPECIAL, where in the latter > case, refKind=special but we use an InterfaceMethodRef? > > On 4/27/2018 1:31 PM, Vicente Romero wrote: >> Hi all, >> >> Please review the current proposal of the constants API, which are >> nominal descriptor types defined in pkg java.lang.invoke.constant. The >> code can be found at [1]. This API is being developed in the context >> of JEP 303: Intrinsics for the LDC and INVOKEDYNAMIC Instructions [2] >> >> Thanks in advance for your comments, >> Vicente >> >> [1] http://cr.openjdk.java.net/~vromero/constant.api/webrev.00 > > [2] http://openjdk.java.net/jeps/303 From john.r.rose at oracle.com Mon Jun 4 23:00:11 2018 From: john.r.rose at oracle.com (John Rose) Date: Mon, 4 Jun 2018 16:00:11 -0700 Subject: [constables] RFR of constants API In-Reply-To: <714a3a32-f318-4b46-f8a1-012f8e3cae3e@oracle.com> References: <451987dd-9371-552f-908d-e57fdc1f09ff@oracle.com> <714a3a32-f318-4b46-f8a1-012f8e3cae3e@oracle.com> Message-ID: <7DB40C6C-7926-424C-B902-8E5A4C5618E6@oracle.com> On Jun 4, 2018, at 2:54 PM, Brian Goetz wrote: > > One of the inputs to a MHDesc is a Kind enum constant. Currently, they map 1:1 with refKind, but it seems to me we need to differentiate between INTERFACE_VIRTUAL and INTERFACE_SPECIAL, where in the latter case, refKind=special but we use an InterfaceMethodRef? Yes, I advise that. Something like: + public enum Kind { + /** A method handle for a method invoked as with {@code invokestatic} */ + STATIC(REF_invokeStatic), + /** A method handle for a method invoked as with {@code invokevirtual} */ + VIRTUAL(REF_invokeVirtual), + /** A method handle for a method invoked as with {@code invokeinterface} */ + INTERFACE_VIRTUAL(REF_invokeInterface, true), + /** A method handle for a class method invoked as with {@code invokespecial} */ + SPECIAL(REF_invokeSpecial), + /** A method handle for an interface method invoked as with {@code invokespecial} */ + INTERFACE_SPECIAL(REF_invokeSpecial, true), + /** A method handle for a constructor */ + CONSTRUCTOR(REF_newInvokeSpecial), ?where the second constructor argument sets the "it's an interface" bit, checked downstream when choosing CONSTANT_Methodref or CONSTANT_InterfaceMethodref. ? John P.S. At one point I thought it might be useful if the ClassDesc carried a tentative "opinion" about whether it will resolve to an interface or not. The meaning of the bit could be "if true I know this will resolve to an interface, else you can assume it's a class". It could provide a default setting for that boolean when the time comes to choose between a CONSTANT_Methodref or a CONSTANT_InterfaceMethodref. The interface bit would be set for ConstantDescs.CR_List and the like. Also if there were a ClassDesc.classToRef function it could fill in this bit. But there isn't, except in test code, for various reasons related to use case analysis of intrinsics and side effects. So it's hard to justify, since other places where ClassDescs are created are from strings, where there is no meaningful way to check for an interface. -------------- next part -------------- An HTML attachment was scrubbed... URL: From vicente.romero at oracle.com Mon Jun 4 23:18:55 2018 From: vicente.romero at oracle.com (Vicente Romero) Date: Mon, 4 Jun 2018 19:18:55 -0400 Subject: [constables] RFR of constants API In-Reply-To: <714a3a32-f318-4b46-f8a1-012f8e3cae3e@oracle.com> References: <451987dd-9371-552f-908d-e57fdc1f09ff@oracle.com> <714a3a32-f318-4b46-f8a1-012f8e3cae3e@oracle.com> Message-ID: <1e6e98c9-5821-04e2-45e2-2c06d54a0417@oracle.com> On 06/04/2018 05:54 PM, Brian Goetz wrote: > Robert Field raised the following possible bug in the API of > MethodHandleDesc. > > A Constant_MethodHandle_info has the following contents: > ? refKind > ? reference to MethodRef or InterfaceMethodRef > ? reference to NameAndType > > Most of these map directly; we extract refKind from Kind, we extract > name from name, we extract type descriptor from type. But, it doesn't > seem like there's a way to express both (refkind=invokespecial, > Constant_MethodRef_info) and (refkind=invokevirtual, > Constant_InterfaceMethodRef_info). > > One of the inputs to a MHDesc is a Kind enum constant.? Currently, > they map 1:1 with refKind, but it seems to me we need to differentiate > between INTERFACE_VIRTUAL and INTERFACE_SPECIAL, where in the latter > case, refKind=special but we use an InterfaceMethodRef? I will fix this, Thanks, Vicente > > On 4/27/2018 1:31 PM, Vicente Romero wrote: >> Hi all, >> >> Please review the current proposal of the constants API, which are >> nominal descriptor types defined in pkg java.lang.invoke.constant. >> The code can be found at [1]. This API is being developed in the >> context of JEP 303: Intrinsics for the LDC and INVOKEDYNAMIC >> Instructions [2] >> >> Thanks in advance for your comments, >> Vicente >> >> [1] http://cr.openjdk.java.net/~vromero/constant.api/webrev.00 >> [2] http://openjdk.java.net/jeps/303 > From james.laskey at oracle.com Thu Jun 7 13:11:01 2018 From: james.laskey at oracle.com (Jim Laskey) Date: Thu, 7 Jun 2018 10:11:01 -0300 Subject: Raw String Literals indentation management Message-ID: This topic died down while we were off doing other things including some more research, consequently Raw String Literals will miss the JDK 11 train. We have introduced some new String methods in JDK 11 (and one Predicate method) that will help us along the way (used in some of the examples below.) String::repeat(int n) String::strip(), String::stripLeading(), String::stripTrailing() String::isBlank() String::lines() Predicate::not(Predicate target) We propose three new Raw String Literal related string methods and plus a power tool; String indent(int n) String indent() Stream lines(LinesOptions... options) String transform(Function f) Generalized Indentation String::indent(int n) can be used to "add to? or" remove from" a fixed amount of indentation on each line. n > 0 adds, n < 0 removes, n == 0 neutral. Example: String a = ` abc def ghi `.indent(4); Result: abc def ghi Ex. String b = ` abc def ghi `.indent(-4); Result: abc def ghi Notes: - Tabs, as all other white space characters, are treated as one space. The only viable alternative is to introduce String::detab/String::entab (which may be reasonable.) - String::indent(int n)also works with strings without line terminators - String::indent(int n) does not crop blank lines. This keeps the method revelant to all strings, not just Raw String Literals. Implementation: /** * When applied to a string, modifies the indentation * of each line based on parameter {@code n}. *

* If {@code n > 0} then {@code n} spaces {@code u+0020} * are inserted at the beginning of each line. * {@link String#isBlank() blank lines} are unaffected. *

* If {@code n < 0} then {@code n} * {@link Character#isWhitespace(int) white space characters} * are removed from the beginning of each line. If a given line * does not contain sufficient white space then all leading * {@link Character#isWhitespace(int) white space characters} * are removed. *

* If {@code n == 0} then indentation remains unchanged, but other * transformations, such as line termination, still take affect. *

* @apinote All * {@link Character#isWhitespace(int) white space characters}, * including tab, are treated as a single space. *

* @apiNote The all line terminators in the result will be * replaced with line feed {@code "\n"} ({@code U+000A}). * * @param n number of leading white space characters * to adjust * * @return string with indentation modified. * * @see Character#isWhitespace(int) * @see String#lines() * * @since 11 */ public String indent(int n) { return isEmpty() ? "" : indent(n, false); } private String indent(int n, boolean skipBlanks) { if (isMultiline()) { Stream stream = skipBlanks ? lines(LinesOptions.ONE_LEADING_TRAILING) : lines(); if (n > 0) { final String spaces = " ".repeat(n); stream = stream.map(s -> s.isBlank() ? s : spaces + s); } else if (n == Integer.MIN_VALUE) { stream = stream.map(s -> s.stripLeading()); } else if (n < 0) { stream = stream.map(s -> s.substring(Math.min(-n, s.indexOfNonWhitespace()))); } return stream.collect(Collectors.joining("\n", "", "\n")); } else { if (n > 0) { return " ".repeat(n) + this; } if (n == Integer.MIN_VALUE) { return stripLeading(); } if (n < 0) { return substring(Math.min(-n, indexOfNonWhitespace())); } return this; } } Raw String Literal Conventional Form and Blank Lines Prior e-mails discussed the conventional form of multi-line Raw String Literals. I listed several examples, but I think the open and close delimiters ?bracketing? string body form seemed to satisfy most commenters. Example: String c = ` abc def ghi `; Unfortunately, doing so introduces additional leading and trailing blank lines that the developer may not have intended to be part of the string. To handle this issue, we propose String::lines(LinesOptions... options). String::lines(LinesOptions... options)returns a stream of substrings extracted from the string partitioned by line terminators with options to remove blank lines before creating the stream. This allows Raw String Literal transformations using String::lines to remain single pass. We realize this is a little rough around the edges, but gets us close to the goal. Example: System.out.println(` abc def ghi `.lines(LinesOptions.ONE_LEADING_TRAILING).count()); Result: 3 Implementation: /** * The constants of this enumerated type provide fine * control over the content of the string stream produced * by the {@link String#lines(LinesOptions)} method. */ public enum LinesOptions { /** * Remove one leading blank line from the stream if present. */ ONE_LEADING, /** * Remove one trailing blank line from the stream if present. */ ONE_TRAILING, /** * Remove one leading blank line and one trailing blank line * from the stream if present. */ ONE_LEADING_TRAILING, /** * Remove all leading blank lines from the stream. */ ALL_LEADING, /** * Remove all trailing blank lines from the stream. */ ALL_TRAILING, /** * Remove all leading and trailing blank lines from the * stream. */ ALL_LEADING_TRAILING, /** * Remove all blank lines from the stream. */ ALL_BLANKS } /** * Returns a stream of substrings extracted from this string * partitioned by line terminators. *

* Line terminators recognized are line feed * {@code "\n"} ({@code U+000A}), * carriage return * {@code "\r"} ({@code U+000D}) * and a carriage return followed immediately by a line feed * {@code "\r\n"} ({@code U+000D U+000A}). *

* The stream returned by this method contains each line of * this string that is terminated by a line terminator except that * the last line can either be terminated by a line terminator or the * end of the string. * The lines in the stream are in the order in which * they occur in this string and do not include the line terminators * partitioning the lines. *

* The {@code options} vararg can be used to specify filtering of * certain lines from the resulting stream. * * @implNote This method provides better performance than * split("\R") by supplying elements lazily and * by faster search of new line terminators. * * @param options a vararg of {@link LinesOptions} used to * control the selection of lines returned * by the stream * * @return the stream of strings extracted from this string * partitioned by line terminators * * @since 11 */ public Stream lines(LinesOptions... options) { Raw String Literal Magic Remove Indentation String::indent() (was String::stripIndent) determines an "n" that left justifies lines without loss of relative indentation. Example: String d = ` abc def ghi `.indent(); Result: abc def ghi That is, indent(-16). Notes: - Raw String Literals are String::indent()'s primary use case. - String::indent() removes the first and last lines if blank, that is lines(LinesOptions.ONE_LEADING_TRAILING), as per the Raw String Literal Conventional Form and Blank Lines topic. - All white spaces are treated equally. There was a discussion about only removing leading white space only if the leading white space matched the "determinant" string's leading white space. The problem is there is often no such string. Example: String x = " \ta\n\t b\n". Both lines have an equal number of leading white spaces. Which one is determinant? - Additional indentation can be added by chaining String::indent() with String::indent(int n). Example: String e = ` abc def ghi `.indent().indent(4); Result: abc def ghi Implementation: /** * When applied to a string, left justifies * lines without loss of relative indentation. This is * accomplished by removing an equal number of * {@link Character#isWhitespace(int) white space} characters * from each line so that at least one line has a non-white * space character in the left-most position. * First and last blank lines introduced to allow * bracketing delimiters to appear on separate source lines * are also removed. *

* @apinote All * {@link Character#isWhitespace(int) white space characters}, * including tab, are treated as a single space. *

* @apiNote The all line terminators in the result will be * replaced with line feed {@code "\n"} ({@code U+000A}). * * @return string left justified * * @see Character#isWhitespace(int) * @see String#indent(int) * @see String#lines() * @see String#lines(LinesOptions... options) * * @since 11 */public String indent() { if (isEmpty()) { return ""; } int min = lines().skip(1) .filter(not(String::isEmpty)) .mapToInt(String::indexOfNonWhitespace) .min() .orElse(0); return indent(-min, true); } I should mention that concerns about compile time verses runtime costs of transforming Raw String Literals will be mitigated by "JEP 303: Intrinsics for the LDC and INVOKEDYNAMIC Instructions? http://openjdk.java.net/jeps/303 . That is, stripping of indentation by indent() will occur at compile time. Custom Indentation Management In prior discussions, we included String::stripMarkers(String leftMarker, String rightMarker) as a means to manage indentation. There was a general feeling, at the time, that String::indent() (then String::stripIndent()) would dominate use and String::stripMarkers less so. We propose that we drop String::stripMarkers and provide a more customizable indentation management using String::lines(LinesOptions... options)and String::transform(Function f). The String::transform(Function f) method allows the application of a string transformation function ?in chain?. Example: public class MyClass { private static final String MARGIN_MARKER= "| "; public String stripMargin(String string) { return lines(LinesOptions.ONE_LEADING_TRAILING) .map(String::strip) .map(s -> s.startsWith(MARGIN_MARKER) ? s.substring(MARGIN_MARKER.length()) : s) .collect(Collectors.joining("\n", "", "\n")); } String f = ` | The content of | the string `.transform(MyClass::stripMargin); Result: The content of the string Implementation: /** * This method allows the application of a function to {@code this} * string. The function should expect a single String argument * and produce a String result. * * @param f functional interface to a apply * * @return the string result of applying the function to this string * * @see java.util.function.Function * * @since 11 */ public String transform(Function f) { return f.apply(this); } -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Thu Jun 7 13:37:05 2018 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 7 Jun 2018 09:37:05 -0400 Subject: Raw String Literals indentation management In-Reply-To: References: Message-ID: This is shaping up nicely. (Subjectively, I like that indent() seems much less obtrusive than before.) It would be great to take the catalog of examples and show what they come out to under indent() in this scheme? > On Jun 7, 2018, at 9:11 AM, Jim Laskey wrote: > > This topic died down while we were off doing other things including some more research, consequently Raw String Literals will miss the JDK 11 train. > > We have introduced some new String methods in JDK 11 (and one Predicate method) that will help us along the way (used in some of the examples below.) > > String::repeat(int n) > String::strip(), String::stripLeading(), String::stripTrailing() > String::isBlank() > String::lines() > Predicate::not(Predicate target) > > We propose three new Raw String Literal related string methods and plus a power tool; > > String indent(int n) > String indent() > Stream lines(LinesOptions... options) > > String transform(Function f) > > > Generalized Indentation > > String::indent(int n) can be used to "add to? or" remove from" a fixed amount of indentation on each line. n > 0 adds, n < 0 removes, n == 0 neutral. > > Example: > > String a = > ` > abc > def > ghi > `.indent(4); > > Result: > > abc > def > ghi > > > Ex. > > String b = > ` > abc > def > ghi > `.indent(-4); > > Result: > > abc > def > ghi > > Notes: > - Tabs, as all other white space characters, are treated as one space. The only viable alternative is to introduce String::detab/String::entab (which may be reasonable.) > - String::indent(int n)also works with strings without line terminators > - String::indent(int n) does not crop blank lines. This keeps the method revelant to all strings, not just Raw String Literals. > > Implementation: > > /** > * When applied to a string, modifies the indentation > * of each line based on parameter {@code n}. > *

> * If {@code n > 0} then {@code n} spaces {@code u+0020} > * are inserted at the beginning of each line. > * {@link String#isBlank() blank lines} are unaffected. > *

> * If {@code n < 0} then {@code n} > * {@link Character#isWhitespace(int) white space characters} > * are removed from the beginning of each line. If a given line > * does not contain sufficient white space then all leading > * {@link Character#isWhitespace(int) white space characters} > * are removed. > *

> * If {@code n == 0} then indentation remains unchanged, but other > * transformations, such as line termination, still take affect. > *

> * @apinote All > * {@link Character#isWhitespace(int) white space characters}, > * including tab, are treated as a single space. > *

> * @apiNote The all line terminators in the result will be > * replaced with line feed {@code "\n"} ({@code U+000A}). > * > * @param n number of leading white space characters > * to adjust > * > * @return string with indentation modified. > * > * @see Character#isWhitespace(int) > * @see String#lines() > * > * @since 11 > */ > public String indent(int n) { > return isEmpty() ? "" : indent(n, false); > } > > private String indent(int n, boolean skipBlanks) { > if (isMultiline()) { > Stream stream = skipBlanks ? lines(LinesOptions.ONE_LEADING_TRAILING) > : lines(); > if (n > 0) { > final String spaces = " ".repeat(n); > stream = stream.map(s -> s.isBlank() ? s : spaces + s); > } else if (n == Integer.MIN_VALUE) { > stream = stream.map(s -> s.stripLeading()); > } else if (n < 0) { > stream = stream.map(s -> s.substring(Math.min(-n, s.indexOfNonWhitespace()))); > } > return stream.collect(Collectors.joining("\n", "", "\n")); > } else { > if (n > 0) { > return " ".repeat(n) + this; > } > if (n == Integer.MIN_VALUE) { > return stripLeading(); > } > if (n < 0) { > return substring(Math.min(-n, indexOfNonWhitespace())); > } > return this; > } > } > > > Raw String Literal Conventional Form and Blank Lines > > Prior e-mails discussed the conventional form of multi-line Raw String Literals. I listed several examples, but I think the open and close delimiters ?bracketing? string body form seemed to satisfy most commenters. > > Example: > > String c = ` > abc > def > ghi > `; > > Unfortunately, doing so introduces additional leading and trailing blank lines that the developer may not have intended to be part of the string. To handle this issue, we propose String::lines(LinesOptions... options). String::lines(LinesOptions... options)returns a stream of substrings extracted from the string partitioned by line terminators with options to remove blank lines before creating the stream. This allows Raw String Literal transformations using String::lines to remain single pass. We realize this is a little rough around the edges, but gets us close to the goal. > > Example: > > System.out.println(` > abc > def > ghi > `.lines(LinesOptions.ONE_LEADING_TRAILING).count()); > > Result: > 3 > > Implementation: > > /** > * The constants of this enumerated type provide fine > * control over the content of the string stream produced > * by the {@link String#lines(LinesOptions)} method. > */ > public enum LinesOptions { > /** > * Remove one leading blank line from the stream if present. > */ > ONE_LEADING, > /** > * Remove one trailing blank line from the stream if present. > */ > ONE_TRAILING, > /** > * Remove one leading blank line and one trailing blank line > * from the stream if present. > */ > ONE_LEADING_TRAILING, > /** > * Remove all leading blank lines from the stream. > */ > ALL_LEADING, > /** > * Remove all trailing blank lines from the stream. > */ > ALL_TRAILING, > /** > * Remove all leading and trailing blank lines from the > * stream. > */ > ALL_LEADING_TRAILING, > /** > * Remove all blank lines from the stream. > */ > ALL_BLANKS > } > > /** > * Returns a stream of substrings extracted from this string > * partitioned by line terminators. > *

> * Line terminators recognized are line feed > * {@code "\n"} ({@code U+000A}), > * carriage return > * {@code "\r"} ({@code U+000D}) > * and a carriage return followed immediately by a line feed > * {@code "\r\n"} ({@code U+000D U+000A}). > *

> * The stream returned by this method contains each line of > * this string that is terminated by a line terminator except that > * the last line can either be terminated by a line terminator or the > * end of the string. > * The lines in the stream are in the order in which > * they occur in this string and do not include the line terminators > * partitioning the lines. > *

> * The {@code options} vararg can be used to specify filtering of > * certain lines from the resulting stream. > * > * @implNote This method provides better performance than > * split("\R") by supplying elements lazily and > * by faster search of new line terminators. > * > * @param options a vararg of {@link LinesOptions} used to > * control the selection of lines returned > * by the stream > * > * @return the stream of strings extracted from this string > * partitioned by line terminators > * > * @since 11 > */ > public Stream lines(LinesOptions... options) { > > > Raw String Literal Magic Remove Indentation > > String::indent() (was String::stripIndent) determines an "n" that left justifies lines without loss of relative indentation. > > Example: > > String d = ` > abc > def > ghi > `.indent(); > > Result: > abc > def > ghi > > That is, indent(-16). > > Notes: > - Raw String Literals are String::indent()'s primary use case. > - String::indent() removes the first and last lines if blank, that is lines(LinesOptions.ONE_LEADING_TRAILING), as per the Raw String Literal Conventional Form and Blank Lines topic. > - All white spaces are treated equally. There was a discussion about only removing leading white space only if the leading white space matched the "determinant" string's leading white space. The problem is there is often no such string. Example: String x = " \ta\n\t b\n". Both lines have an equal number of leading white spaces. Which one is determinant? > - Additional indentation can be added by chaining String::indent() with String::indent(int n). > > Example: > > String e = ` > abc > def > ghi > `.indent().indent(4); > > Result: > abc > def > ghi > > Implementation: > > /** > * When applied to a string, left justifies > * lines without loss of relative indentation. This is > * accomplished by removing an equal number of > * {@link Character#isWhitespace(int) white space} characters > * from each line so that at least one line has a non-white > * space character in the left-most position. > * First and last blank lines introduced to allow > * bracketing delimiters to appear on separate source lines > * are also removed. > *

> * @apinote All > * {@link Character#isWhitespace(int) white space characters}, > * including tab, are treated as a single space. > *

> * @apiNote The all line terminators in the result will be > * replaced with line feed {@code "\n"} ({@code U+000A}). > * > * @return string left justified > * > * @see Character#isWhitespace(int) > * @see String#indent(int) > * @see String#lines() > * @see String#lines(LinesOptions... options) > * > * @since 11 > */public String indent() { > if (isEmpty()) { > return ""; > } > int min = lines().skip(1) > .filter(not(String::isEmpty)) > .mapToInt(String::indexOfNonWhitespace) > .min() > .orElse(0); > return indent(-min, true); > } > > I should mention that concerns about compile time verses runtime costs of transforming Raw String Literals will be mitigated by "JEP 303: Intrinsics for the LDC and INVOKEDYNAMIC Instructions? http://openjdk.java.net/jeps/303 . That is, stripping of indentation by indent() will occur at compile time. > > > Custom Indentation Management > > In prior discussions, we included String::stripMarkers(String leftMarker, String rightMarker) as a means to manage indentation. There was a general feeling, at the time, that String::indent() (then String::stripIndent()) would dominate use and String::stripMarkers less so. We propose that we drop String::stripMarkers and provide a more customizable indentation management using String::lines(LinesOptions... options)and String::transform(Function f). > > The String::transform(Function f) method allows the application of a string transformation function ?in chain?. > > Example: > > public class MyClass { > private static final String MARGIN_MARKER= "| "; > public String stripMargin(String string) { > return lines(LinesOptions.ONE_LEADING_TRAILING) > .map(String::strip) > .map(s -> s.startsWith(MARGIN_MARKER) ? s.substring(MARGIN_MARKER.length()) : s) > .collect(Collectors.joining("\n", "", "\n")); > } > > String f = ` > | The content of > | the string > `.transform(MyClass::stripMargin); > > Result: > > The content of > the string > > > Implementation: > > /** > * This method allows the application of a function to {@code this} > * string. The function should expect a single String argument > * and produce a String result. > * > * @param f functional interface to a apply > * > * @return the string result of applying the function to this string > * > * @see java.util.function.Function > * > * @since 11 > */ > public String transform(Function f) { > return f.apply(this); > } > -------------- next part -------------- An HTML attachment was scrubbed... URL: From guy.steele at oracle.com Thu Jun 7 16:39:09 2018 From: guy.steele at oracle.com (Guy Steele) Date: Thu, 7 Jun 2018 12:39:09 -0400 Subject: Raw String Literals indentation management In-Reply-To: References: Message-ID: > On Jun 7, 2018, at 9:11 AM, Jim Laskey wrote: > > This topic died down while we were off doing other things including some more research, consequently Raw String Literals will miss the JDK 11 train. > > We have introduced some new String methods in JDK 11 (and one Predicate method) that will help us along the way (used in some of the examples below.) Very nice. I do note that the meaning of .indent() is not immediately apparent from the name, especially because if it does anything at all, it *removes* some indentation. Allow me to suggest eliminating .indent(), and replacing it with .reindent(n), which has the effect of .indent().indent(n) (in other words, it "changes the indentation to be n?). If you don?t like the name ?reinvent?, it could be ?leftMargin?. The name ?lines? is similarly uninformative, and the LinesOptions business seems kind of clunky: useful if we expect to be ?computing lines options?, but if not, I would rather see System.out.println(` abc def ghi `.removeOneLeadingBlankLine().removeOneTrailingBlankLine().count()); and other available methods are removeAllLeadingBlankLines() removeAllTrailingBlankLines() removeAllSurroundingBlankLines() removeAllBlankLines() which I think would cover 99.9% of uses. ?Guy P.S. In doc for .indent(int n), "take affect? => ?take effect?. -------------- next part -------------- An HTML attachment was scrubbed... URL: From james.laskey at oracle.com Thu Jun 7 17:42:08 2018 From: james.laskey at oracle.com (Jim Laskey) Date: Thu, 7 Jun 2018 14:42:08 -0300 Subject: Raw String Literals indentation management In-Reply-To: References: Message-ID: > On Jun 7, 2018, at 1:39 PM, Guy Steele wrote: > > >> On Jun 7, 2018, at 9:11 AM, Jim Laskey > wrote: >> >> This topic died down while we were off doing other things including some more research, consequently Raw String Literals will miss the JDK 11 train. >> >> We have introduced some new String methods in JDK 11 (and one Predicate method) that will help us along the way (used in some of the examples below.) > > Very nice. I do note that the meaning of .indent() is not immediately apparent from the name, especially because if it does anything at all, it *removes* some indentation. > > Allow me to suggest eliminating .indent(), and replacing it with .reindent(n), which has the effect of .indent().indent(n) (in other words, it "changes the indentation to be n?). If you don?t like the name ?reinvent?, it could be ?leftMargin?. Part of the goal was to shorten the name to reduce the annoyance quotient. ?reindent? speaks to me more than ?leftMargin? (starts searching thesaurus.) The combo makes sense too. Then you start thinking in terms of indent is just reindent without the magic. An alternative ?think? is string.indent().indent(n) -> string.indent(string.minIndent() + n). Unfortunately, this pattern doesn?t chain well. > > The name ?lines? is similarly uninformative, and the LinesOptions business seems kind of clunky: useful if we expect to be ?computing lines options?, but if not, I would rather see > > System.out.println(` > abc > def > ghi > `.removeOneLeadingBlankLine().removeOneTrailingBlankLine().count()); > > and other available methods are > > removeAllLeadingBlankLines() > removeAllTrailingBlankLines() > removeAllSurroundingBlankLines() > removeAllBlankLines() > > which I think would cover 99.9% of uses. Any shorter naming options? Assuming you are returning Strings, this would be costly (string copying), but reasonable. If you are returning Stream, first and last combinators really suck with streams. That is, you have to make full passes with each call. Internally, I have it implemented as .lines(int maxLeadingBlanksRemoved, int maxTrailingBlanksRemoved) System.out.println(` abc def ghi `.lines(1,1)).count(); This keeps everything single pass. > > ?Guy > > P.S. In doc for .indent(int n), "take affect? => ?take effect?. > D?oh thanks. Cheers, ? Jim -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Thu Jun 7 17:48:05 2018 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 7 Jun 2018 13:48:05 -0400 Subject: Raw String Literals indentation management In-Reply-To: References: Message-ID: <0AAAF6D9-D970-4B5A-8930-C092CD0798CD@oracle.com> > > Part of the goal was to shorten the name to reduce the annoyance quotient. ?reindent? speaks to me more than ?leftMargin? (starts searching thesaurus.) The combo makes sense too. Then you start thinking in terms of indent is just reindent without the magic. reindent() is OK by me; its a little longer but it says what it means, and still less fussy than trimMargin() or autoMagicReindent(). undent() is shorter, but sounds more like what happens at an auto-body repair shop :) -------------- next part -------------- An HTML attachment was scrubbed... URL: From guy.steele at oracle.com Thu Jun 7 17:48:51 2018 From: guy.steele at oracle.com (Guy Steele) Date: Thu, 7 Jun 2018 13:48:51 -0400 Subject: Raw String Literals indentation management In-Reply-To: References: Message-ID: > On Jun 7, 2018, at 1:42 PM, Jim Laskey wrote: > >> On Jun 7, 2018, at 1:39 PM, Guy Steele > wrote: >> >>> On Jun 7, 2018, at 9:11 AM, Jim Laskey > wrote: >> . . . >> The name ?lines? is similarly uninformative, and the LinesOptions business seems kind of clunky: useful if we expect to be ?computing lines options?, but if not, I would rather see >> >> System.out.println(` >> abc >> def >> ghi >> `.removeOneLeadingBlankLine().removeOneTrailingBlankLine().count()); >> >> and other available methods are >> >> removeAllLeadingBlankLines() >> removeAllTrailingBlankLines() >> removeAllSurroundingBlankLines() >> removeAllBlankLines() >> >> which I think would cover 99.9% of uses. > > Any shorter naming options? Sure: remove the word ?All? from those last four names. Too bad we don;t have a single word for ?Blank Line?. > Assuming you are returning Strings, this would be costly (string copying), but reasonable. I was relying on your earlier assertion that in most cases there transformations get done at compile time . . . > > If you are returning Stream, first and last combinators really suck with streams. That is, you have to make full passes with each call. . . . but, d?oh! I forgot that streams are involved here. ?Never mind.? So you really would need individual methods, and that?s pushing the number of methods pretty high. > > Internally, I have it implemented as .lines(int maxLeadingBlanksRemoved, int maxTrailingBlanksRemoved) > > System.out.println(` > abc > def > ghi > `.lines(1,1)).count(); > > This keeps everything single pass. -------------- next part -------------- An HTML attachment was scrubbed... URL: From guy.steele at oracle.com Thu Jun 7 17:49:49 2018 From: guy.steele at oracle.com (Guy Steele) Date: Thu, 7 Jun 2018 13:49:49 -0400 Subject: Raw String Literals indentation management In-Reply-To: <0AAAF6D9-D970-4B5A-8930-C092CD0798CD@oracle.com> References: <0AAAF6D9-D970-4B5A-8930-C092CD0798CD@oracle.com> Message-ID: <5E51CDFB-928C-46D3-9B2E-4C669E24FE08@oracle.com> > On Jun 7, 2018, at 1:48 PM, Brian Goetz wrote: > >> >> Part of the goal was to shorten the name to reduce the annoyance quotient. ?reindent? speaks to me more than ?leftMargin? (starts searching thesaurus.) The combo makes sense too. Then you start thinking in terms of indent is just reindent without the magic. > > reindent() is OK by me; its a little longer but it says what it means, and still less fussy than trimMargin() or autoMagicReindent(). > > undent() is shorter, but sounds more like what happens at an auto-body repair shop :) Or redent(), which happens a week later. :-) -------------- next part -------------- An HTML attachment was scrubbed... URL: From james.laskey at oracle.com Fri Jun 8 14:36:25 2018 From: james.laskey at oracle.com (Jim Laskey) Date: Fri, 8 Jun 2018 11:36:25 -0300 Subject: Raw String Literals indentation management In-Reply-To: <5E51CDFB-928C-46D3-9B2E-4C669E24FE08@oracle.com> References: <0AAAF6D9-D970-4B5A-8930-C092CD0798CD@oracle.com> <5E51CDFB-928C-46D3-9B2E-4C669E24FE08@oracle.com> Message-ID: We?re going to try align. Example: String a = ` abc def ghi `.align(); Result: abc def ghi Example: String b = ` abc def ghi `.align(4); Result: abc def ghi Example: String c = ` abc def ghi `.align(-1); Result: abc def ghi Implementation: /** * When applied to a string, left justifies * lines without loss of relative indentation. This is * accomplished by removing an equal number of * {@link Character#isWhitespace(int) white space} characters * from each line so that at least one line has a non-white * space character in the left-most position. * The result is realigned by indenting {@code n} * {@link Character#isWhitespace(int) white space} * characters. * First and last blank lines introduced to allow * bracketing delimiters to appear on separate source lines * are also removed. *

* @apinote All * {@link Character#isWhitespace(int) white space characters}, * including tab, are treated as a single space. *

* @apiNote The all line terminators in the result will be * replaced with line feed {@code "\n"} ({@code U+000A}). * * @param n number of leading white space characters * to adjust * * @return string left justified * * @see Character#isWhitespace(int) * @see String#indent(int) * @see String#lines() * @see String#lines(LinesOptions... options) * * @since 11 */ public String align(int n) { if (isEmpty()) { return ""; } int min = lines().skip(1) .filter(not(String::isEmpty)) .mapToInt(String::indexOfNonWhitespace) .min() .orElse(0); return indent(n - min, true); } /** * When applied to a string, left justifies * lines without loss of relative indentation. This is * accomplished by removing an equal number of * {@link Character#isWhitespace(int) white space} characters * from each line so that at least one line has a non-white * space character in the left-most position. * First and last blank lines introduced to allow * bracketing delimiters to appear on separate source lines * are also removed. *

* @apinote All * {@link Character#isWhitespace(int) white space characters}, * including tab, are treated as a single space. *

* @apiNote The all line terminators in the result will be * replaced with line feed {@code "\n"} ({@code U+000A}). * * @return string left justified * * @see Character#isWhitespace(int) * @see String#indent(int) * @see String#lines() * @see String#lines(LinesOptions... options) * * @since 11 */ public String align() { return align(0); } With lines, we?re going to drop the LinesOptions silliness and just go with maxLeading and maxTrailing. Example: int d = ` abc def ghi `.lines().count(); Result: 5 Example: int e = ` abc def ghi `.lines(1, 1).count(); Result: 3 Example: int f = ` abc def ghi `.lines(Integer.Max_VALUE,Integer.Max_VALUE).count(); Result: 3 Implementation: /** * Returns a stream of substrings extracted from this string * partitioned by line terminators. *

* Line terminators recognized are line feed * {@code "\n"} ({@code U+000A}), * carriage return * {@code "\r"} ({@code U+000D}) * and a carriage return followed immediately by a line feed * {@code "\r\n"} ({@code U+000D U+000A}). *

* The stream returned by this method contains each line of * this string that is terminated by a line terminator except that * the last line can either be terminated by a line terminator or the * end of the string. * The lines in the stream are in the order in which * they occur in this string and do not include the line terminators * partitioning the lines. *

* The {@code maxLeading} and {@code maxTrailing} arguments can be * used to remove incidental blank lines from the beginning and * end of a multi-line sequence. A value of {@code 1} will remove * at most one blank line. A value of {@link Integer.MAX_VALUE} * will all leading or trailing blank lines. * * @implNote This method provides better performance than * split("\R") by supplying elements lazily and * by faster search of new line terminators. * * @param maxLeading the maximum number of leading blank lines * to remove * * @param maxTrailing the maximum number of trailing blank lines * to remove * * @return the stream of strings extracted from this string * partitioned by line terminators * * @throws IllegalArgumentException if {@code maxLeading} or * {@code maxTrailing} is negative. * * @since 11 */ public Stream lines(int maxLeading, int maxTrailing) { if (maxLeading < 0) { throw new IllegalArgumentException("maxLeading is negative: " + maxLeading); } if (maxTrailing < 0) { throw new IllegalArgumentException("maxTrailing is negative: " + maxTrailing); } Stream stream = isLatin1() ? StringLatin1.lines(value, maxLeading, maxTrailing) : StringUTF16.lines(value, maxLeading, maxTrailing); return stream; } /** * Returns a stream of substrings extracted from this string * partitioned by line terminators. *

* Line terminators recognized are line feed * {@code "\n"} ({@code U+000A}), * carriage return * {@code "\r"} ({@code U+000D}) * and a carriage return followed immediately by a line feed * {@code "\r\n"} ({@code U+000D U+000A}). *

* The stream returned by this method contains each line of * this string that is terminated by a line terminator except that * the last line can either be terminated by a line terminator or the * end of the string. * The lines in the stream are in the order in which * they occur in this string and do not include the line terminators * partitioning the lines. * * @implNote This method provides better performance than * split("\R") by supplying elements lazily and * by faster search of new line terminators. * * @return the stream of strings extracted from this string * partitioned by line terminators * * @since 11 */ public Stream lines() { return lines(0, 0); } > On Jun 7, 2018, at 2:49 PM, Guy Steele wrote: > > >> On Jun 7, 2018, at 1:48 PM, Brian Goetz > wrote: >> >>> >>> Part of the goal was to shorten the name to reduce the annoyance quotient. ?reindent? speaks to me more than ?leftMargin? (starts searching thesaurus.) The combo makes sense too. Then you start thinking in terms of indent is just reindent without the magic. >> >> reindent() is OK by me; its a little longer but it says what it means, and still less fussy than trimMargin() or autoMagicReindent(). >> >> undent() is shorter, but sounds more like what happens at an auto-body repair shop :) > > Or redent(), which happens a week later. :-) > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Fri Jun 8 14:44:14 2018 From: brian.goetz at oracle.com (Brian Goetz) Date: Fri, 8 Jun 2018 10:44:14 -0400 Subject: Raw String Literals indentation management In-Reply-To: References: <0AAAF6D9-D970-4B5A-8930-C092CD0798CD@oracle.com> <5E51CDFB-928C-46D3-9B2E-4C669E24FE08@oracle.com> Message-ID: <2A9D0ACC-CFAE-4069-83B5-DC40A0E2AC41@oracle.com> Align sounds good for the magic method, but for the add/remove version, align n sounds a little more like an absolute rather than relative adjustment? ?Line it up with a min of n leading spaces?? Sent from my iPad > On Jun 8, 2018, at 10:36 AM, Jim Laskey wrote: > > We?re going to try align. > > Example: > > String a = ` > abc > def > ghi > `.align(); > > Result: > abc > def > ghi > > Example: > > String b = ` > abc > def > ghi > `.align(4); > Result: > abc > def > ghi > > Example: > > String c = ` > abc > def > ghi > `.align(-1); > Result: > abc > def > ghi > > Implementation: > > /** > * When applied to a string, left justifies > * lines without loss of relative indentation. This is > * accomplished by removing an equal number of > * {@link Character#isWhitespace(int) white space} characters > * from each line so that at least one line has a non-white > * space character in the left-most position. > * The result is realigned by indenting {@code n} > * {@link Character#isWhitespace(int) white space} > * characters. > * First and last blank lines introduced to allow > * bracketing delimiters to appear on separate source lines > * are also removed. > *

> * @apinote All > * {@link Character#isWhitespace(int) white space characters}, > * including tab, are treated as a single space. > *

> * @apiNote The all line terminators in the result will be > * replaced with line feed {@code "\n"} ({@code U+000A}). > * > * @param n number of leading white space characters > * to adjust > * > * @return string left justified > * > * @see Character#isWhitespace(int) > * @see String#indent(int) > * @see String#lines() > * @see String#lines(LinesOptions... options) > * > * @since 11 > */ > public String align(int n) { > if (isEmpty()) { > return ""; > } > int min = lines().skip(1) > .filter(not(String::isEmpty)) > .mapToInt(String::indexOfNonWhitespace) > .min() > .orElse(0); > return indent(n - min, true); > } > > /** > * When applied to a string, left justifies > * lines without loss of relative indentation. This is > * accomplished by removing an equal number of > * {@link Character#isWhitespace(int) white space} characters > * from each line so that at least one line has a non-white > * space character in the left-most position. > * First and last blank lines introduced to allow > * bracketing delimiters to appear on separate source lines > * are also removed. > *

> * @apinote All > * {@link Character#isWhitespace(int) white space characters}, > * including tab, are treated as a single space. > *

> * @apiNote The all line terminators in the result will be > * replaced with line feed {@code "\n"} ({@code U+000A}). > * > * @return string left justified > * > * @see Character#isWhitespace(int) > * @see String#indent(int) > * @see String#lines() > * @see String#lines(LinesOptions... options) > * > * @since 11 > */ > public String align() { > return align(0); > } > > With lines, we?re going to drop the LinesOptions silliness and just go with maxLeading and maxTrailing. > > Example: > > int d = ` > abc > def > ghi > `.lines().count(); > > Result: > 5 > > Example: > > int e = ` > abc > def > ghi > `.lines(1, 1).count(); > > Result: > 3 > > Example: > > int f = ` > > > > abc > def > ghi > > > > `.lines(Integer.Max_VALUE,Integer.Max_VALUE).count(); > > Result: > 3 > > Implementation: > > /** > * Returns a stream of substrings extracted from this string > * partitioned by line terminators. > *

> * Line terminators recognized are line feed > * {@code "\n"} ({@code U+000A}), > * carriage return > * {@code "\r"} ({@code U+000D}) > * and a carriage return followed immediately by a line feed > * {@code "\r\n"} ({@code U+000D U+000A}). > *

> * The stream returned by this method contains each line of > * this string that is terminated by a line terminator except that > * the last line can either be terminated by a line terminator or the > * end of the string. > * The lines in the stream are in the order in which > * they occur in this string and do not include the line terminators > * partitioning the lines. > *

> * The {@code maxLeading} and {@code maxTrailing} arguments can be > * used to remove incidental blank lines from the beginning and > * end of a multi-line sequence. A value of {@code 1} will remove > * at most one blank line. A value of {@link Integer.MAX_VALUE} > * will all leading or trailing blank lines. > * > * @implNote This method provides better performance than > * split("\R") by supplying elements lazily and > * by faster search of new line terminators. > * > * @param maxLeading the maximum number of leading blank lines > * to remove > * > * @param maxTrailing the maximum number of trailing blank lines > * to remove > * > * @return the stream of strings extracted from this string > * partitioned by line terminators > * > * @throws IllegalArgumentException if {@code maxLeading} or > * {@code maxTrailing} is negative. > * > * @since 11 > */ > public Stream lines(int maxLeading, int maxTrailing) { > if (maxLeading < 0) { > throw new IllegalArgumentException("maxLeading is negative: " + maxLeading); > } > if (maxTrailing < 0) { > throw new IllegalArgumentException("maxTrailing is negative: " + maxTrailing); > } > Stream stream = isLatin1() ? StringLatin1.lines(value, maxLeading, maxTrailing) > : StringUTF16.lines(value, maxLeading, maxTrailing); > return stream; > } > > /** > * Returns a stream of substrings extracted from this string > * partitioned by line terminators. > *

> * Line terminators recognized are line feed > * {@code "\n"} ({@code U+000A}), > * carriage return > * {@code "\r"} ({@code U+000D}) > * and a carriage return followed immediately by a line feed > * {@code "\r\n"} ({@code U+000D U+000A}). > *

> * The stream returned by this method contains each line of > * this string that is terminated by a line terminator except that > * the last line can either be terminated by a line terminator or the > * end of the string. > * The lines in the stream are in the order in which > * they occur in this string and do not include the line terminators > * partitioning the lines. > * > * @implNote This method provides better performance than > * split("\R") by supplying elements lazily and > * by faster search of new line terminators. > * > * @return the stream of strings extracted from this string > * partitioned by line terminators > * > * @since 11 > */ > public Stream lines() { > return lines(0, 0); > } > >>> On Jun 7, 2018, at 2:49 PM, Guy Steele wrote: >>> >>> >>>> On Jun 7, 2018, at 1:48 PM, Brian Goetz wrote: >>>> >>>> >>>> Part of the goal was to shorten the name to reduce the annoyance quotient. ?reindent? speaks to me more than ?leftMargin? (starts searching thesaurus.) The combo makes sense too. Then you start thinking in terms of indent is just reindent without the magic. >>> >>> reindent() is OK by me; its a little longer but it says what it means, and still less fussy than trimMargin() or autoMagicReindent(). >>> >>> undent() is shorter, but sounds more like what happens at an auto-body repair shop :) >> >> Or redent(), which happens a week later. :-) >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From james.laskey at oracle.com Fri Jun 8 14:57:14 2018 From: james.laskey at oracle.com (Jim Laskey) Date: Fri, 8 Jun 2018 11:57:14 -0300 Subject: Raw String Literals indentation management In-Reply-To: <2A9D0ACC-CFAE-4069-83B5-DC40A0E2AC41@oracle.com> References: <0AAAF6D9-D970-4B5A-8930-C092CD0798CD@oracle.com> <5E51CDFB-928C-46D3-9B2E-4C669E24FE08@oracle.com> <2A9D0ACC-CFAE-4069-83B5-DC40A0E2AC41@oracle.com> Message-ID: <5F3215FF-5A00-45BC-BF1B-550505289EC6@oracle.com> align(n) == align().indent(n) as per Guy?s suggestion. Another interpretation is, align to the nth column. align(12) will align the relatively to column 12. ? Jim > On Jun 8, 2018, at 11:44 AM, Brian Goetz wrote: > > Align sounds good for the magic method, but for the add/remove version, align n sounds a little more like an absolute rather than relative adjustment? ?Line it up with a min of n leading spaces?? > > Sent from my iPad > > On Jun 8, 2018, at 10:36 AM, Jim Laskey > wrote: > >> We?re going to try align. >> >> Example: >> >> String a = ` >> abc >> def >> ghi >> `.align(); >> >> Result: >> abc >> def >> ghi >> >> Example: >> >> String b = ` >> abc >> def >> ghi >> `.align(4); >> Result: >> abc >> def >> ghi >> >> Example: >> >> String c = ` >> abc >> def >> ghi >> `.align(-1); >> Result: >> abc >> def >> ghi >> >> Implementation: >> >> /** >> * When applied to a string, left justifies >> * lines without loss of relative indentation. This is >> * accomplished by removing an equal number of >> * {@link Character#isWhitespace(int) white space} characters >> * from each line so that at least one line has a non-white >> * space character in the left-most position. >> * The result is realigned by indenting {@code n} >> * {@link Character#isWhitespace(int) white space} >> * characters. >> * First and last blank lines introduced to allow >> * bracketing delimiters to appear on separate source lines >> * are also removed. >> *

>> * @apinote All >> * {@link Character#isWhitespace(int) white space characters}, >> * including tab, are treated as a single space. >> *

>> * @apiNote The all line terminators in the result will be >> * replaced with line feed {@code "\n"} ({@code U+000A}). >> * >> * @param n number of leading white space characters >> * to adjust >> * >> * @return string left justified >> * >> * @see Character#isWhitespace(int) >> * @see String#indent(int) >> * @see String#lines() >> * @see String#lines(LinesOptions... options) >> * >> * @since 11 >> */ >> public String align(int n) { >> if (isEmpty()) { >> return ""; >> } >> int min = lines().skip(1) >> .filter(not(String::isEmpty)) >> .mapToInt(String::indexOfNonWhitespace) >> .min() >> .orElse(0); >> return indent(n - min, true); >> } >> >> /** >> * When applied to a string, left justifies >> * lines without loss of relative indentation. This is >> * accomplished by removing an equal number of >> * {@link Character#isWhitespace(int) white space} characters >> * from each line so that at least one line has a non-white >> * space character in the left-most position. >> * First and last blank lines introduced to allow >> * bracketing delimiters to appear on separate source lines >> * are also removed. >> *

>> * @apinote All >> * {@link Character#isWhitespace(int) white space characters}, >> * including tab, are treated as a single space. >> *

>> * @apiNote The all line terminators in the result will be >> * replaced with line feed {@code "\n"} ({@code U+000A}). >> * >> * @return string left justified >> * >> * @see Character#isWhitespace(int) >> * @see String#indent(int) >> * @see String#lines() >> * @see String#lines(LinesOptions... options) >> * >> * @since 11 >> */ >> public String align() { >> return align(0); >> } >> >> With lines, we?re going to drop the LinesOptions silliness and just go with maxLeading and maxTrailing. >> >> Example: >> >> int d = ` >> abc >> def >> ghi >> `.lines().count(); >> >> Result: >> 5 >> >> Example: >> >> int e = ` >> abc >> def >> ghi >> `.lines(1, 1).count(); >> >> Result: >> 3 >> >> Example: >> >> int f = ` >> >> >> >> abc >> def >> ghi >> >> >> >> `.lines(Integer.Max_VALUE,Integer.Max_VALUE).count(); >> >> Result: >> 3 >> >> Implementation: >> >> /** >> * Returns a stream of substrings extracted from this string >> * partitioned by line terminators. >> *

>> * Line terminators recognized are line feed >> * {@code "\n"} ({@code U+000A}), >> * carriage return >> * {@code "\r"} ({@code U+000D}) >> * and a carriage return followed immediately by a line feed >> * {@code "\r\n"} ({@code U+000D U+000A}). >> *

>> * The stream returned by this method contains each line of >> * this string that is terminated by a line terminator except that >> * the last line can either be terminated by a line terminator or the >> * end of the string. >> * The lines in the stream are in the order in which >> * they occur in this string and do not include the line terminators >> * partitioning the lines. >> *

>> * The {@code maxLeading} and {@code maxTrailing} arguments can be >> * used to remove incidental blank lines from the beginning and >> * end of a multi-line sequence. A value of {@code 1} will remove >> * at most one blank line. A value of {@link Integer.MAX_VALUE} >> * will all leading or trailing blank lines. >> * >> * @implNote This method provides better performance than >> * split("\R") by supplying elements lazily and >> * by faster search of new line terminators. >> * >> * @param maxLeading the maximum number of leading blank lines >> * to remove >> * >> * @param maxTrailing the maximum number of trailing blank lines >> * to remove >> * >> * @return the stream of strings extracted from this string >> * partitioned by line terminators >> * >> * @throws IllegalArgumentException if {@code maxLeading} or >> * {@code maxTrailing} is negative. >> * >> * @since 11 >> */ >> public Stream lines(int maxLeading, int maxTrailing) { >> if (maxLeading < 0) { >> throw new IllegalArgumentException("maxLeading is negative: " + maxLeading); >> } >> if (maxTrailing < 0) { >> throw new IllegalArgumentException("maxTrailing is negative: " + maxTrailing); >> } >> Stream stream = isLatin1() ? StringLatin1.lines(value, maxLeading, maxTrailing) >> : StringUTF16.lines(value, maxLeading, maxTrailing); >> return stream; >> } >> >> /** >> * Returns a stream of substrings extracted from this string >> * partitioned by line terminators. >> *

>> * Line terminators recognized are line feed >> * {@code "\n"} ({@code U+000A}), >> * carriage return >> * {@code "\r"} ({@code U+000D}) >> * and a carriage return followed immediately by a line feed >> * {@code "\r\n"} ({@code U+000D U+000A}). >> *

>> * The stream returned by this method contains each line of >> * this string that is terminated by a line terminator except that >> * the last line can either be terminated by a line terminator or the >> * end of the string. >> * The lines in the stream are in the order in which >> * they occur in this string and do not include the line terminators >> * partitioning the lines. >> * >> * @implNote This method provides better performance than >> * split("\R") by supplying elements lazily and >> * by faster search of new line terminators. >> * >> * @return the stream of strings extracted from this string >> * partitioned by line terminators >> * >> * @since 11 >> */ >> public Stream lines() { >> return lines(0, 0); >> } >> >>> On Jun 7, 2018, at 2:49 PM, Guy Steele > wrote: >>> >>> >>>> On Jun 7, 2018, at 1:48 PM, Brian Goetz > wrote: >>>> >>>>> >>>>> Part of the goal was to shorten the name to reduce the annoyance quotient. ?reindent? speaks to me more than ?leftMargin? (starts searching thesaurus.) The combo makes sense too. Then you start thinking in terms of indent is just reindent without the magic. >>>> >>>> reindent() is OK by me; its a little longer but it says what it means, and still less fussy than trimMargin() or autoMagicReindent(). >>>> >>>> undent() is shorter, but sounds more like what happens at an auto-body repair shop :) >>> >>> Or redent(), which happens a week later. :-) >>> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From guy.steele at oracle.com Fri Jun 8 15:43:12 2018 From: guy.steele at oracle.com (Guy Steele) Date: Fri, 8 Jun 2018 11:43:12 -0400 Subject: Raw String Literals indentation management In-Reply-To: References: <0AAAF6D9-D970-4B5A-8930-C092CD0798CD@oracle.com> <5E51CDFB-928C-46D3-9B2E-4C669E24FE08@oracle.com> Message-ID: I think ?align? is an excellent choice of method name. In the doc, "The result is realigned? => "The result is then realigned? ? And the simplification to just `.lines(m, n)` is welcome. If you really want to eliminate blank lines in the middle, just say `.lines(m, n).filter(not(String::isEmpty))`. ?Guy > On Jun 8, 2018, at 10:36 AM, Jim Laskey wrote: > > We?re going to try align. > > Example: > > String a = ` > abc > def > ghi > `.align(); > > Result: > abc > def > ghi > > Example: > > String b = ` > abc > def > ghi > `.align(4); > Result: > abc > def > ghi > > Example: > > String c = ` > abc > def > ghi > `.align(-1); > Result: > abc > def > ghi > > Implementation: > > /** > * When applied to a string, left justifies > * lines without loss of relative indentation. This is > * accomplished by removing an equal number of > * {@link Character#isWhitespace(int) white space} characters > * from each line so that at least one line has a non-white > * space character in the left-most position. > * The result is realigned by indenting {@code n} > * {@link Character#isWhitespace(int) white space} > * characters. > * First and last blank lines introduced to allow > * bracketing delimiters to appear on separate source lines > * are also removed. > *

> * @apinote All > * {@link Character#isWhitespace(int) white space characters}, > * including tab, are treated as a single space. > *

> * @apiNote The all line terminators in the result will be > * replaced with line feed {@code "\n"} ({@code U+000A}). > * > * @param n number of leading white space characters > * to adjust > * > * @return string left justified > * > * @see Character#isWhitespace(int) > * @see String#indent(int) > * @see String#lines() > * @see String#lines(LinesOptions... options) > * > * @since 11 > */ > public String align(int n) { > if (isEmpty()) { > return ""; > } > int min = lines().skip(1) > .filter(not(String::isEmpty)) > .mapToInt(String::indexOfNonWhitespace) > .min() > .orElse(0); > return indent(n - min, true); > } > > /** > * When applied to a string, left justifies > * lines without loss of relative indentation. This is > * accomplished by removing an equal number of > * {@link Character#isWhitespace(int) white space} characters > * from each line so that at least one line has a non-white > * space character in the left-most position. > * First and last blank lines introduced to allow > * bracketing delimiters to appear on separate source lines > * are also removed. > *

> * @apinote All > * {@link Character#isWhitespace(int) white space characters}, > * including tab, are treated as a single space. > *

> * @apiNote The all line terminators in the result will be > * replaced with line feed {@code "\n"} ({@code U+000A}). > * > * @return string left justified > * > * @see Character#isWhitespace(int) > * @see String#indent(int) > * @see String#lines() > * @see String#lines(LinesOptions... options) > * > * @since 11 > */ > public String align() { > return align(0); > } > > With lines, we?re going to drop the LinesOptions silliness and just go with maxLeading and maxTrailing. > > Example: > > int d = ` > abc > def > ghi > `.lines().count(); > > Result: > 5 > > Example: > > int e = ` > abc > def > ghi > `.lines(1, 1).count(); > > Result: > 3 > > Example: > > int f = ` > > > > abc > def > ghi > > > > `.lines(Integer.Max_VALUE,Integer.Max_VALUE).count(); > > Result: > 3 > > Implementation: > > /** > * Returns a stream of substrings extracted from this string > * partitioned by line terminators. > *

> * Line terminators recognized are line feed > * {@code "\n"} ({@code U+000A}), > * carriage return > * {@code "\r"} ({@code U+000D}) > * and a carriage return followed immediately by a line feed > * {@code "\r\n"} ({@code U+000D U+000A}). > *

> * The stream returned by this method contains each line of > * this string that is terminated by a line terminator except that > * the last line can either be terminated by a line terminator or the > * end of the string. > * The lines in the stream are in the order in which > * they occur in this string and do not include the line terminators > * partitioning the lines. > *

> * The {@code maxLeading} and {@code maxTrailing} arguments can be > * used to remove incidental blank lines from the beginning and > * end of a multi-line sequence. A value of {@code 1} will remove > * at most one blank line. A value of {@link Integer.MAX_VALUE} > * will all leading or trailing blank lines. > * > * @implNote This method provides better performance than > * split("\R") by supplying elements lazily and > * by faster search of new line terminators. > * > * @param maxLeading the maximum number of leading blank lines > * to remove > * > * @param maxTrailing the maximum number of trailing blank lines > * to remove > * > * @return the stream of strings extracted from this string > * partitioned by line terminators > * > * @throws IllegalArgumentException if {@code maxLeading} or > * {@code maxTrailing} is negative. > * > * @since 11 > */ > public Stream lines(int maxLeading, int maxTrailing) { > if (maxLeading < 0) { > throw new IllegalArgumentException("maxLeading is negative: " + maxLeading); > } > if (maxTrailing < 0) { > throw new IllegalArgumentException("maxTrailing is negative: " + maxTrailing); > } > Stream stream = isLatin1() ? StringLatin1.lines(value, maxLeading, maxTrailing) > : StringUTF16.lines(value, maxLeading, maxTrailing); > return stream; > } > > /** > * Returns a stream of substrings extracted from this string > * partitioned by line terminators. > *

> * Line terminators recognized are line feed > * {@code "\n"} ({@code U+000A}), > * carriage return > * {@code "\r"} ({@code U+000D}) > * and a carriage return followed immediately by a line feed > * {@code "\r\n"} ({@code U+000D U+000A}). > *

> * The stream returned by this method contains each line of > * this string that is terminated by a line terminator except that > * the last line can either be terminated by a line terminator or the > * end of the string. > * The lines in the stream are in the order in which > * they occur in this string and do not include the line terminators > * partitioning the lines. > * > * @implNote This method provides better performance than > * split("\R") by supplying elements lazily and > * by faster search of new line terminators. > * > * @return the stream of strings extracted from this string > * partitioned by line terminators > * > * @since 11 > */ > public Stream lines() { > return lines(0, 0); > } > >> On Jun 7, 2018, at 2:49 PM, Guy Steele > wrote: >> >> >>> On Jun 7, 2018, at 1:48 PM, Brian Goetz > wrote: >>> >>>> >>>> Part of the goal was to shorten the name to reduce the annoyance quotient. ?reindent? speaks to me more than ?leftMargin? (starts searching thesaurus.) The combo makes sense too. Then you start thinking in terms of indent is just reindent without the magic. >>> >>> reindent() is OK by me; its a little longer but it says what it means, and still less fussy than trimMargin() or autoMagicReindent(). >>> >>> undent() is shorter, but sounds more like what happens at an auto-body repair shop :) >> >> Or redent(), which happens a week later. :-) >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From james.laskey at oracle.com Fri Jun 8 16:19:27 2018 From: james.laskey at oracle.com (Jim Laskey) Date: Fri, 8 Jun 2018 13:19:27 -0300 Subject: Raw String Literals indentation management In-Reply-To: References: <0AAAF6D9-D970-4B5A-8930-C092CD0798CD@oracle.com> <5E51CDFB-928C-46D3-9B2E-4C669E24FE08@oracle.com> Message-ID: <07276BC9-D8D0-4793-87FA-EE531B72D8B4@oracle.com> Thank you. > On Jun 8, 2018, at 12:43 PM, Guy Steele wrote: > > I think ?align? is an excellent choice of method name. > > In the doc, "The result is realigned? => "The result is then realigned? ? > > And the simplification to just `.lines(m, n)` is welcome. If you really want to eliminate blank lines in the middle, just say `.lines(m, n).filter(not(String::isEmpty))`. > > ?Guy > >> On Jun 8, 2018, at 10:36 AM, Jim Laskey > wrote: >> >> We?re going to try align. >> >> Example: >> >> String a = ` >> abc >> def >> ghi >> `.align(); >> >> Result: >> abc >> def >> ghi >> >> Example: >> >> String b = ` >> abc >> def >> ghi >> `.align(4); >> Result: >> abc >> def >> ghi >> >> Example: >> >> String c = ` >> abc >> def >> ghi >> `.align(-1); >> Result: >> abc >> def >> ghi >> >> Implementation: >> >> /** >> * When applied to a string, left justifies >> * lines without loss of relative indentation. This is >> * accomplished by removing an equal number of >> * {@link Character#isWhitespace(int) white space} characters >> * from each line so that at least one line has a non-white >> * space character in the left-most position. >> * The result is realigned by indenting {@code n} >> * {@link Character#isWhitespace(int) white space} >> * characters. >> * First and last blank lines introduced to allow >> * bracketing delimiters to appear on separate source lines >> * are also removed. >> *

>> * @apinote All >> * {@link Character#isWhitespace(int) white space characters}, >> * including tab, are treated as a single space. >> *

>> * @apiNote The all line terminators in the result will be >> * replaced with line feed {@code "\n"} ({@code U+000A}). >> * >> * @param n number of leading white space characters >> * to adjust >> * >> * @return string left justified >> * >> * @see Character#isWhitespace(int) >> * @see String#indent(int) >> * @see String#lines() >> * @see String#lines(LinesOptions... options) >> * >> * @since 11 >> */ >> public String align(int n) { >> if (isEmpty()) { >> return ""; >> } >> int min = lines().skip(1) >> .filter(not(String::isEmpty)) >> .mapToInt(String::indexOfNonWhitespace) >> .min() >> .orElse(0); >> return indent(n - min, true); >> } >> >> /** >> * When applied to a string, left justifies >> * lines without loss of relative indentation. This is >> * accomplished by removing an equal number of >> * {@link Character#isWhitespace(int) white space} characters >> * from each line so that at least one line has a non-white >> * space character in the left-most position. >> * First and last blank lines introduced to allow >> * bracketing delimiters to appear on separate source lines >> * are also removed. >> *

>> * @apinote All >> * {@link Character#isWhitespace(int) white space characters}, >> * including tab, are treated as a single space. >> *

>> * @apiNote The all line terminators in the result will be >> * replaced with line feed {@code "\n"} ({@code U+000A}). >> * >> * @return string left justified >> * >> * @see Character#isWhitespace(int) >> * @see String#indent(int) >> * @see String#lines() >> * @see String#lines(LinesOptions... options) >> * >> * @since 11 >> */ >> public String align() { >> return align(0); >> } >> >> With lines, we?re going to drop the LinesOptions silliness and just go with maxLeading and maxTrailing. >> >> Example: >> >> int d = ` >> abc >> def >> ghi >> `.lines().count(); >> >> Result: >> 5 >> >> Example: >> >> int e = ` >> abc >> def >> ghi >> `.lines(1, 1).count(); >> >> Result: >> 3 >> >> Example: >> >> int f = ` >> >> >> >> abc >> def >> ghi >> >> >> >> `.lines(Integer.Max_VALUE,Integer.Max_VALUE).count(); >> >> Result: >> 3 >> >> Implementation: >> >> /** >> * Returns a stream of substrings extracted from this string >> * partitioned by line terminators. >> *

>> * Line terminators recognized are line feed >> * {@code "\n"} ({@code U+000A}), >> * carriage return >> * {@code "\r"} ({@code U+000D}) >> * and a carriage return followed immediately by a line feed >> * {@code "\r\n"} ({@code U+000D U+000A}). >> *

>> * The stream returned by this method contains each line of >> * this string that is terminated by a line terminator except that >> * the last line can either be terminated by a line terminator or the >> * end of the string. >> * The lines in the stream are in the order in which >> * they occur in this string and do not include the line terminators >> * partitioning the lines. >> *

>> * The {@code maxLeading} and {@code maxTrailing} arguments can be >> * used to remove incidental blank lines from the beginning and >> * end of a multi-line sequence. A value of {@code 1} will remove >> * at most one blank line. A value of {@link Integer.MAX_VALUE} >> * will all leading or trailing blank lines. >> * >> * @implNote This method provides better performance than >> * split("\R") by supplying elements lazily and >> * by faster search of new line terminators. >> * >> * @param maxLeading the maximum number of leading blank lines >> * to remove >> * >> * @param maxTrailing the maximum number of trailing blank lines >> * to remove >> * >> * @return the stream of strings extracted from this string >> * partitioned by line terminators >> * >> * @throws IllegalArgumentException if {@code maxLeading} or >> * {@code maxTrailing} is negative. >> * >> * @since 11 >> */ >> public Stream lines(int maxLeading, int maxTrailing) { >> if (maxLeading < 0) { >> throw new IllegalArgumentException("maxLeading is negative: " + maxLeading); >> } >> if (maxTrailing < 0) { >> throw new IllegalArgumentException("maxTrailing is negative: " + maxTrailing); >> } >> Stream stream = isLatin1() ? StringLatin1.lines(value, maxLeading, maxTrailing) >> : StringUTF16.lines(value, maxLeading, maxTrailing); >> return stream; >> } >> >> /** >> * Returns a stream of substrings extracted from this string >> * partitioned by line terminators. >> *

>> * Line terminators recognized are line feed >> * {@code "\n"} ({@code U+000A}), >> * carriage return >> * {@code "\r"} ({@code U+000D}) >> * and a carriage return followed immediately by a line feed >> * {@code "\r\n"} ({@code U+000D U+000A}). >> *

>> * The stream returned by this method contains each line of >> * this string that is terminated by a line terminator except that >> * the last line can either be terminated by a line terminator or the >> * end of the string. >> * The lines in the stream are in the order in which >> * they occur in this string and do not include the line terminators >> * partitioning the lines. >> * >> * @implNote This method provides better performance than >> * split("\R") by supplying elements lazily and >> * by faster search of new line terminators. >> * >> * @return the stream of strings extracted from this string >> * partitioned by line terminators >> * >> * @since 11 >> */ >> public Stream lines() { >> return lines(0, 0); >> } >> >>> On Jun 7, 2018, at 2:49 PM, Guy Steele > wrote: >>> >>> >>>> On Jun 7, 2018, at 1:48 PM, Brian Goetz > wrote: >>>> >>>>> >>>>> Part of the goal was to shorten the name to reduce the annoyance quotient. ?reindent? speaks to me more than ?leftMargin? (starts searching thesaurus.) The combo makes sense too. Then you start thinking in terms of indent is just reindent without the magic. >>>> >>>> reindent() is OK by me; its a little longer but it says what it means, and still less fussy than trimMargin() or autoMagicReindent(). >>>> >>>> undent() is shorter, but sounds more like what happens at an auto-body repair shop :) >>> >>> Or redent(), which happens a week later. :-) >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From james.laskey at oracle.com Fri Jun 8 17:47:55 2018 From: james.laskey at oracle.com (Jim Laskey) Date: Fri, 8 Jun 2018 14:47:55 -0300 Subject: Raw String Literals indentation management In-Reply-To: References: <0AAAF6D9-D970-4B5A-8930-C092CD0798CD@oracle.com> <5E51CDFB-928C-46D3-9B2E-4C669E24FE08@oracle.com> Message-ID: Example: String c = ` abc def ghi `.align(-1); Result: abc def ghi Pasting error. should have been three leading spaces. That is, align() on column zero would have left 4 spaces in front of each line. 4 - 1 == 3, hence 3 spaces. Using the columns interpretation, the lines are aligned one column to the left of the page; c.align().indent(-1) or c.lines(1, 1).indent(-1-19). Another perspective, Example: String x = ` abc def ghi `.align(-4); Result: abc def ghi - line 0 would land in column zero by the alignment but can not move any further. - line 1 would land in column four by the alignment and then indent(-4) ending up in column zero - line 2 would land in column eight by the alignment and then indent(-4) ending up in column four > On Jun 8, 2018, at 11:36 AM, Jim Laskey wrote: > > We?re going to try align. > > Example: > > String a = ` > abc > def > ghi > `.align(); > > Result: > abc > def > ghi > > Example: > > String b = ` > abc > def > ghi > `.align(4); > Result: > abc > def > ghi > > Example: > > String c = ` > abc > def > ghi > `.align(-1); > Result: > abc > def > ghi > > Implementation: > > /** > * When applied to a string, left justifies > * lines without loss of relative indentation. This is > * accomplished by removing an equal number of > * {@link Character#isWhitespace(int) white space} characters > * from each line so that at least one line has a non-white > * space character in the left-most position. > * The result is realigned by indenting {@code n} > * {@link Character#isWhitespace(int) white space} > * characters. > * First and last blank lines introduced to allow > * bracketing delimiters to appear on separate source lines > * are also removed. > *

> * @apinote All > * {@link Character#isWhitespace(int) white space characters}, > * including tab, are treated as a single space. > *

> * @apiNote The all line terminators in the result will be > * replaced with line feed {@code "\n"} ({@code U+000A}). > * > * @param n number of leading white space characters > * to adjust > * > * @return string left justified > * > * @see Character#isWhitespace(int) > * @see String#indent(int) > * @see String#lines() > * @see String#lines(LinesOptions... options) > * > * @since 11 > */ > public String align(int n) { > if (isEmpty()) { > return ""; > } > int min = lines().skip(1) > .filter(not(String::isEmpty)) > .mapToInt(String::indexOfNonWhitespace) > .min() > .orElse(0); > return indent(n - min, true); > } > > /** > * When applied to a string, left justifies > * lines without loss of relative indentation. This is > * accomplished by removing an equal number of > * {@link Character#isWhitespace(int) white space} characters > * from each line so that at least one line has a non-white > * space character in the left-most position. > * First and last blank lines introduced to allow > * bracketing delimiters to appear on separate source lines > * are also removed. > *

> * @apinote All > * {@link Character#isWhitespace(int) white space characters}, > * including tab, are treated as a single space. > *

> * @apiNote The all line terminators in the result will be > * replaced with line feed {@code "\n"} ({@code U+000A}). > * > * @return string left justified > * > * @see Character#isWhitespace(int) > * @see String#indent(int) > * @see String#lines() > * @see String#lines(LinesOptions... options) > * > * @since 11 > */ > public String align() { > return align(0); > } > > With lines, we?re going to drop the LinesOptions silliness and just go with maxLeading and maxTrailing. > > Example: > > int d = ` > abc > def > ghi > `.lines().count(); > > Result: > 5 > > Example: > > int e = ` > abc > def > ghi > `.lines(1, 1).count(); > > Result: > 3 > > Example: > > int f = ` > > > > abc > def > ghi > > > > `.lines(Integer.Max_VALUE,Integer.Max_VALUE).count(); > > Result: > 3 > > Implementation: > > /** > * Returns a stream of substrings extracted from this string > * partitioned by line terminators. > *

> * Line terminators recognized are line feed > * {@code "\n"} ({@code U+000A}), > * carriage return > * {@code "\r"} ({@code U+000D}) > * and a carriage return followed immediately by a line feed > * {@code "\r\n"} ({@code U+000D U+000A}). > *

> * The stream returned by this method contains each line of > * this string that is terminated by a line terminator except that > * the last line can either be terminated by a line terminator or the > * end of the string. > * The lines in the stream are in the order in which > * they occur in this string and do not include the line terminators > * partitioning the lines. > *

> * The {@code maxLeading} and {@code maxTrailing} arguments can be > * used to remove incidental blank lines from the beginning and > * end of a multi-line sequence. A value of {@code 1} will remove > * at most one blank line. A value of {@link Integer.MAX_VALUE} > * will all leading or trailing blank lines. > * > * @implNote This method provides better performance than > * split("\R") by supplying elements lazily and > * by faster search of new line terminators. > * > * @param maxLeading the maximum number of leading blank lines > * to remove > * > * @param maxTrailing the maximum number of trailing blank lines > * to remove > * > * @return the stream of strings extracted from this string > * partitioned by line terminators > * > * @throws IllegalArgumentException if {@code maxLeading} or > * {@code maxTrailing} is negative. > * > * @since 11 > */ > public Stream lines(int maxLeading, int maxTrailing) { > if (maxLeading < 0) { > throw new IllegalArgumentException("maxLeading is negative: " + maxLeading); > } > if (maxTrailing < 0) { > throw new IllegalArgumentException("maxTrailing is negative: " + maxTrailing); > } > Stream stream = isLatin1() ? StringLatin1.lines(value, maxLeading, maxTrailing) > : StringUTF16.lines(value, maxLeading, maxTrailing); > return stream; > } > > /** > * Returns a stream of substrings extracted from this string > * partitioned by line terminators. > *

> * Line terminators recognized are line feed > * {@code "\n"} ({@code U+000A}), > * carriage return > * {@code "\r"} ({@code U+000D}) > * and a carriage return followed immediately by a line feed > * {@code "\r\n"} ({@code U+000D U+000A}). > *

> * The stream returned by this method contains each line of > * this string that is terminated by a line terminator except that > * the last line can either be terminated by a line terminator or the > * end of the string. > * The lines in the stream are in the order in which > * they occur in this string and do not include the line terminators > * partitioning the lines. > * > * @implNote This method provides better performance than > * split("\R") by supplying elements lazily and > * by faster search of new line terminators. > * > * @return the stream of strings extracted from this string > * partitioned by line terminators > * > * @since 11 > */ > public Stream lines() { > return lines(0, 0); > } > >> On Jun 7, 2018, at 2:49 PM, Guy Steele > wrote: >> >> >>> On Jun 7, 2018, at 1:48 PM, Brian Goetz > wrote: >>> >>>> >>>> Part of the goal was to shorten the name to reduce the annoyance quotient. ?reindent? speaks to me more than ?leftMargin? (starts searching thesaurus.) The combo makes sense too. Then you start thinking in terms of indent is just reindent without the magic. >>> >>> reindent() is OK by me; its a little longer but it says what it means, and still less fussy than trimMargin() or autoMagicReindent(). >>> >>> undent() is shorter, but sounds more like what happens at an auto-body repair shop :) >> >> Or redent(), which happens a week later. :-) >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From james.laskey at oracle.com Mon Jun 11 16:59:19 2018 From: james.laskey at oracle.com (Jim Laskey) Date: Mon, 11 Jun 2018 13:59:19 -0300 Subject: Raw String Literals indentation management In-Reply-To: References: <0AAAF6D9-D970-4B5A-8930-C092CD0798CD@oracle.com> <5E51CDFB-928C-46D3-9B2E-4C669E24FE08@oracle.com> Message-ID: <792C038A-A6F3-4146-83BD-E26383D5075F@oracle.com> Some follow up. Now that we allow additional indentation to be specified when using .align(n), we?re dropping the ?closing delimiter trick? that was initially proposed. Example: // With the trick of allowing the line that includes the closing quote to influence the indentation. String a = ` abc def ghi `.align(); Result: abc def ghi This was accomplished by only filtering empty lines. public String align(int n) { if (isEmpty()) { return ""; } int min = lines().skip(1) .filter(not(String::isEmpty)) .mapToInt(String::indexOfNonWhitespace) .min() .orElse(0); return indent(n - min, true); } By change the filter to .filter(not(String::isBlank)), we only measure lines that have visible (non-white space) characters and hence ignore the last line. Examples: String a = ` abc def ghi `.align(4); String a = ` abc def ghi `.align(4); String a = ` abc def ghi `.align(4); String a = ` abc def ghi `.align(4); All produce the same result: abc def ghi Note that the first line is skipped so that String a = `abc def ghi`.align(4); String a = `abc def ghi `.align(4); also produces the same result (not enforcing a style convention.) ? Jim > On Jun 8, 2018, at 12:43 PM, Guy Steele wrote: > > I think ?align? is an excellent choice of method name. > > In the doc, "The result is realigned? => "The result is then realigned? ? > > And the simplification to just `.lines(m, n)` is welcome. If you really want to eliminate blank lines in the middle, just say `.lines(m, n).filter(not(String::isEmpty))`. > > ?Guy > >> On Jun 8, 2018, at 10:36 AM, Jim Laskey > wrote: >> >> We?re going to try align. >> >> Example: >> >> String a = ` >> abc >> def >> ghi >> `.align(); >> >> Result: >> abc >> def >> ghi >> >> Example: >> >> String b = ` >> abc >> def >> ghi >> `.align(4); >> Result: >> abc >> def >> ghi >> >> Example: >> >> String c = ` >> abc >> def >> ghi >> `.align(-1); >> Result: >> abc >> def >> ghi >> >> Implementation: >> >> /** >> * When applied to a string, left justifies >> * lines without loss of relative indentation. This is >> * accomplished by removing an equal number of >> * {@link Character#isWhitespace(int) white space} characters >> * from each line so that at least one line has a non-white >> * space character in the left-most position. >> * The result is realigned by indenting {@code n} >> * {@link Character#isWhitespace(int) white space} >> * characters. >> * First and last blank lines introduced to allow >> * bracketing delimiters to appear on separate source lines >> * are also removed. >> *

>> * @apinote All >> * {@link Character#isWhitespace(int) white space characters}, >> * including tab, are treated as a single space. >> *

>> * @apiNote The all line terminators in the result will be >> * replaced with line feed {@code "\n"} ({@code U+000A}). >> * >> * @param n number of leading white space characters >> * to adjust >> * >> * @return string left justified >> * >> * @see Character#isWhitespace(int) >> * @see String#indent(int) >> * @see String#lines() >> * @see String#lines(LinesOptions... options) >> * >> * @since 11 >> */ >> public String align(int n) { >> if (isEmpty()) { >> return ""; >> } >> int min = lines().skip(1) >> .filter(not(String::isEmpty)) >> .mapToInt(String::indexOfNonWhitespace) >> .min() >> .orElse(0); >> return indent(n - min, true); >> } >> >> /** >> * When applied to a string, left justifies >> * lines without loss of relative indentation. This is >> * accomplished by removing an equal number of >> * {@link Character#isWhitespace(int) white space} characters >> * from each line so that at least one line has a non-white >> * space character in the left-most position. >> * First and last blank lines introduced to allow >> * bracketing delimiters to appear on separate source lines >> * are also removed. >> *

>> * @apinote All >> * {@link Character#isWhitespace(int) white space characters}, >> * including tab, are treated as a single space. >> *

>> * @apiNote The all line terminators in the result will be >> * replaced with line feed {@code "\n"} ({@code U+000A}). >> * >> * @return string left justified >> * >> * @see Character#isWhitespace(int) >> * @see String#indent(int) >> * @see String#lines() >> * @see String#lines(LinesOptions... options) >> * >> * @since 11 >> */ >> public String align() { >> return align(0); >> } >> >> With lines, we?re going to drop the LinesOptions silliness and just go with maxLeading and maxTrailing. >> >> Example: >> >> int d = ` >> abc >> def >> ghi >> `.lines().count(); >> >> Result: >> 5 >> >> Example: >> >> int e = ` >> abc >> def >> ghi >> `.lines(1, 1).count(); >> >> Result: >> 3 >> >> Example: >> >> int f = ` >> >> >> >> abc >> def >> ghi >> >> >> >> `.lines(Integer.Max_VALUE,Integer.Max_VALUE).count(); >> >> Result: >> 3 >> >> Implementation: >> >> /** >> * Returns a stream of substrings extracted from this string >> * partitioned by line terminators. >> *

>> * Line terminators recognized are line feed >> * {@code "\n"} ({@code U+000A}), >> * carriage return >> * {@code "\r"} ({@code U+000D}) >> * and a carriage return followed immediately by a line feed >> * {@code "\r\n"} ({@code U+000D U+000A}). >> *

>> * The stream returned by this method contains each line of >> * this string that is terminated by a line terminator except that >> * the last line can either be terminated by a line terminator or the >> * end of the string. >> * The lines in the stream are in the order in which >> * they occur in this string and do not include the line terminators >> * partitioning the lines. >> *

>> * The {@code maxLeading} and {@code maxTrailing} arguments can be >> * used to remove incidental blank lines from the beginning and >> * end of a multi-line sequence. A value of {@code 1} will remove >> * at most one blank line. A value of {@link Integer.MAX_VALUE} >> * will all leading or trailing blank lines. >> * >> * @implNote This method provides better performance than >> * split("\R") by supplying elements lazily and >> * by faster search of new line terminators. >> * >> * @param maxLeading the maximum number of leading blank lines >> * to remove >> * >> * @param maxTrailing the maximum number of trailing blank lines >> * to remove >> * >> * @return the stream of strings extracted from this string >> * partitioned by line terminators >> * >> * @throws IllegalArgumentException if {@code maxLeading} or >> * {@code maxTrailing} is negative. >> * >> * @since 11 >> */ >> public Stream lines(int maxLeading, int maxTrailing) { >> if (maxLeading < 0) { >> throw new IllegalArgumentException("maxLeading is negative: " + maxLeading); >> } >> if (maxTrailing < 0) { >> throw new IllegalArgumentException("maxTrailing is negative: " + maxTrailing); >> } >> Stream stream = isLatin1() ? StringLatin1.lines(value, maxLeading, maxTrailing) >> : StringUTF16.lines(value, maxLeading, maxTrailing); >> return stream; >> } >> >> /** >> * Returns a stream of substrings extracted from this string >> * partitioned by line terminators. >> *

>> * Line terminators recognized are line feed >> * {@code "\n"} ({@code U+000A}), >> * carriage return >> * {@code "\r"} ({@code U+000D}) >> * and a carriage return followed immediately by a line feed >> * {@code "\r\n"} ({@code U+000D U+000A}). >> *

>> * The stream returned by this method contains each line of >> * this string that is terminated by a line terminator except that >> * the last line can either be terminated by a line terminator or the >> * end of the string. >> * The lines in the stream are in the order in which >> * they occur in this string and do not include the line terminators >> * partitioning the lines. >> * >> * @implNote This method provides better performance than >> * split("\R") by supplying elements lazily and >> * by faster search of new line terminators. >> * >> * @return the stream of strings extracted from this string >> * partitioned by line terminators >> * >> * @since 11 >> */ >> public Stream lines() { >> return lines(0, 0); >> } >> >>> On Jun 7, 2018, at 2:49 PM, Guy Steele > wrote: >>> >>> >>>> On Jun 7, 2018, at 1:48 PM, Brian Goetz > wrote: >>>> >>>>> >>>>> Part of the goal was to shorten the name to reduce the annoyance quotient. ?reindent? speaks to me more than ?leftMargin? (starts searching thesaurus.) The combo makes sense too. Then you start thinking in terms of indent is just reindent without the magic. >>>> >>>> reindent() is OK by me; its a little longer but it says what it means, and still less fussy than trimMargin() or autoMagicReindent(). >>>> >>>> undent() is shorter, but sounds more like what happens at an auto-body repair shop :) >>> >>> Or redent(), which happens a week later. :-) >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Jun 11 17:16:29 2018 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 11 Jun 2018 13:16:29 -0400 Subject: Raw String Literals indentation management In-Reply-To: <792C038A-A6F3-4146-83BD-E26383D5075F@oracle.com> References: <0AAAF6D9-D970-4B5A-8930-C092CD0798CD@oracle.com> <5E51CDFB-928C-46D3-9B2E-4C669E24FE08@oracle.com> <792C038A-A6F3-4146-83BD-E26383D5075F@oracle.com> Message-ID: <91831e43-e1b3-5f01-75c3-4eb3865ca80c@oracle.com> OK, so let me summarize and see if I understand it: ?- there are fixed indenting methods, .indent(n), which never touch NLs; ?- the magic align() method _ignores_ blank lines now, uses the non-blank lines to identify a maximal common prefix to remove, and removes that, and then removes a leading blank line if any, and if the trailing line is blank, strips out all whitespace (so it ends in NL); ?- the methods align(n) are just align().indent(n). On 6/11/2018 12:59 PM, Jim Laskey wrote: > Some follow up. Now that we allow additional indentation to be > specified when using .align(n), we?re dropping the ?closing delimiter > trick? that was initially proposed. > > Example: > > ? ? // With the trick of allowing the line that includes the closing > quote to influence the indentation. > ? ? String a = ` > ? ? ? ? ? ? ? ?abc > ? ?def > ? ?ghi > ? ? ? ?`.align(); > > Result: > ? ? abc > ? ? def > ? ? ghi > > This was accomplished by only filtering empty lines. > > public?String align(int?n) { > ? ??if?(isEmpty()) { > ? ? ? ??return?""; > ? ? } > ? ??int?min = lines().skip(1) > *.filter(not(String::isEmpty))* > ?.mapToInt(String::indexOfNonWhitespace) > ? ? ? ? ? ? ? ? ? ? ?.min() > ? ? ? ? ? ? ? ? ? ? ?.orElse(0); > ? ??return?indent(n - min,?true); > } > > By change the filter to .filter(not(String::isBlank)), we only measure > lines that have visible (non-white space) characters and hence ignore > the last line. > > Examples: > > ? ? String a = ` > ? ? ? ? ? ? ? ? ?abc > ? ? ?def > ? ? ?ghi > ? ? ? ?`.align(4); > > ? ? String a = ` > ? ?abc > ? ? ? ? ? ? ? ?def > ? ? ? ? ? ? ? ?ghi > ? ? ?`.align(4); > > ? ? String a = ` > ?abc > ?def > ?ghi > ?`.align(4); > > ? String a = ` > ? ? ? ? ? abc > ? ? ? def > ? ? ? ghi > ?`.align(4); > > All produce the same result: > ? ? abc > ? ? def > ? ? ghi > > Note that the first line is skipped so that > > ? ? String a = `abc > ? ? ? ? ? ? ? def > ? ghi`.align(4); > > ? ? String a = `abc > ? ? ? ? ? ? ? def > ? ghi > `.align(4); > > also produces the same result (not enforcing a style convention.) > > ? Jim > > >> On Jun 8, 2018, at 12:43 PM, Guy Steele > > wrote: >> >> I think ?align? is an excellent choice of method name. >> >> In the doc, "The result is realigned? => "The result is then realigned? ? >> >> And the simplification to just `.lines(m, n)` is welcome. ?If you >> really want to eliminate blank lines in the middle, just say >> `.lines(m, n).filter(not(String::isEmpty))`. >> >> ?Guy >> >>> On Jun 8, 2018, at 10:36 AM, Jim Laskey >> > wrote: >>> >>> We?re going to try align. >>> >>> Example: >>> >>> String a = ` >>> ? ? ? ? ? ?abc >>> ? ? ? ? ? ?def >>> ? ? ? ? ? ?ghi >>> ?`.align(); >>> >>> Result: >>> ? ? abc >>> ? ? def >>> ? ? ghi >>> >>> Example: >>> >>> String b = ` >>> ?abc >>> ?def >>> ?ghi >>> `.align(4); >>> Result: >>> abc >>> def >>> ghi >>> >>> Example: >>> >>> String c = ` >>> ?abc >>> ?def >>> ?ghi >>> `.align(-1); >>> Result: >>> abc >>> def >>> ghi >>> >>> Implementation: >>> >>> /** >>> ?* When applied to a string, left justifies >>> ?* lines without loss of relative indentation. This is >>> ?* accomplished by removing an equal number of >>> ?* {@link?Character#isWhitespace(int) white space} characters >>> ?* from each line so that at least one line has a non-white >>> ?* space character in the left-most position. >>> ?* The result is realigned by indenting {@code?n} >>> ?* {@link?Character#isWhitespace(int) white space} >>> ?* characters. >>> ?* First and last blank lines introduced to allow >>> ?* bracketing ?delimiters to appear on separate source lines >>> ?* are also removed. >>> ?*?

>>> ?*?@apinote?All >>> ?* ?{@link?Character#isWhitespace(int) white space characters}, >>> ?* ? ? ? ? ?including tab, are treated as a single space. >>> ?*?

>>> ?*?@apiNote?The all line terminators in the result will be >>> ?* ? ? ? ? ?replaced with line feed {@code?"\n"} ({@code?U+000A}). >>> ?* >>> ?*?@param?n ?number of leading white space characters >>> ?* ? ? ? ? ? to adjust >>> ?* >>> ?*?@return?string left justified >>> ?* >>> ?*?@see?Character#isWhitespace(int) >>> ?*?@see?String#indent(int) >>> ?*?@see?String#lines() >>> ?*?@see?String#lines(LinesOptions... options) >>> ?* >>> ?*?@since?11 >>> ?*/ >>> public?String align(int?n) { >>> ? ??if?(isEmpty()) { >>> ? ? ? ??return?""; >>> ? ? } >>> ? ??int?min = lines().skip(1) >>> ?.filter(not(String::isEmpty)) >>> ?.mapToInt(String::indexOfNonWhitespace) >>> ? ? ? ? ? ? ? ? ? ? ?.min() >>> ? ? ? ? ? ? ? ? ? ? ?.orElse(0); >>> ? ??return?indent(n - min,?true); >>> } >>> >>> /** >>> ?* When applied to a string, left justifies >>> ?* lines without loss of relative indentation. This is >>> ?* accomplished by removing an equal number of >>> ?* {@link?Character#isWhitespace(int) white space} characters >>> ?* from each line so that at least one line has a non-white >>> ?* space character in the left-most position. >>> ?* First and last blank lines introduced to allow >>> ?* bracketing ?delimiters to appear on separate source lines >>> ?* are also removed. >>> ?*?

>>> ?*?@apinote?All >>> ?* ?{@link?Character#isWhitespace(int) white space characters}, >>> ?* ? ? ? ? ?including tab, are treated as a single space. >>> ?*?

>>> ?*?@apiNote?The all line terminators in the result will be >>> ?* ? ? ? ? ?replaced with line feed {@code?"\n"} ({@code?U+000A}). >>> ?* >>> ?*?@return?string left justified >>> ?* >>> ?*?@see?Character#isWhitespace(int) >>> ?*?@see?String#indent(int) >>> ?*?@see?String#lines() >>> ?*?@see?String#lines(LinesOptions... options) >>> ?* >>> ?*?@since?11 >>> ?*/ >>> public?String align() { >>> ? ??return?align(0); >>> } >>> >>> With lines, we?re going to drop the LinesOptions silliness and just >>> go with maxLeading and maxTrailing. >>> >>> Example: >>> >>> ? ? int d = ` >>> ? ? ? ? abc >>> ? ? ? ? def >>> ? ? ? ? ghi >>> ? ? `.lines().count(); >>> >>> Result: >>> 5 >>> >>> Example: >>> >>> ? ? int e = ` >>> ? ? ? ? abc >>> ? ? ? ? def >>> ? ? ? ? ghi >>> ? ? `.lines(1, 1).count(); >>> >>> Result: >>> 3 >>> >>> Example: >>> >>> ? ? int f = ` >>> >>> >>> >>> ? ? ? ? abc >>> ? ? ? ? def >>> ? ? ? ? ghi >>> >>> >>> >>> `.lines(Integer.Max_VALUE,Integer.Max_VALUE).count(); >>> >>> Result: >>> 3 >>> >>> Implementation: >>> >>> /** >>> ?* Returns a stream of substrings extracted from this string >>> ?* partitioned by line terminators. >>> ?*?

>>> ?* Line terminators recognized are line feed >>> ?* {@code?"\n"} ({@code?U+000A}), >>> ?* carriage return >>> ?* {@code?"\r"} ({@code?U+000D}) >>> ?* and a carriage return followed immediately by a line feed >>> ?* {@code?"\r\n"} ({@code?U+000D U+000A}). >>> ?*?

>>> ?* The stream returned by this method contains each line of >>> ?* this string that is terminated by a line terminator except that >>> ?* the last line can either be terminated by a line terminator or the >>> ?* end of the string. >>> ?* The lines in the stream are in the order in which >>> ?* they occur in this string and do not include the line terminators >>> ?* partitioning the lines. >>> ?*?

>>> ?* The {@code?maxLeading} and {@code?maxTrailing} arguments can be >>> ?* used to remove incidental blank lines from the beginning and >>> ?* end of a multi-line sequence. A value of {@code?1} will remove >>> ?* at most one blank line. A value of {@link?Integer.MAX_VALUE} >>> ?* will all leading or trailing blank lines. >>> ?* >>> ?*?@implNote?This method provides better performance than >>> ?* ? ? ? ? ? split("\R") by supplying elements lazily and >>> ?* ? ? ? ? ? by faster search of new line terminators. >>> ?* >>> ?*?@param ?maxLeading ? the maximum number of leading blank lines >>> ?* ? ? ? ? ? ? ? ? ? ? ?to remove >>> ?* >>> ?*?@param ?maxTrailing ?the maximum number of trailing blank lines >>> ?* ? ? ? ? ? ? ? ? ? ? ?to remove >>> ?* >>> ?*?@return ?the stream of strings extracted from this string >>> ?* ? ? ? ? ?partitioned by line terminators >>> ?* >>> ?*?@throws ?IllegalArgumentException if {@code?maxLeading} or >>> ?* ? ? ? ? ?{@code?maxTrailing} is negative. >>> ?* >>> ?*?@since?11 >>> ?*/ >>> public?Stream lines(int?maxLeading,?int?maxTrailing) { >>> ? ??if?(maxLeading >> ? ? ? ??throw new?IllegalArgumentException("maxLeading is negative: >>> "?+ maxLeading); >>> ? ? } >>> ? ??if?(maxTrailing >> ? ? ? ??throw new?IllegalArgumentException("maxTrailing is negative: >>> "?+ maxTrailing); >>> ? ? } >>> ? ? Stream stream = isLatin1() ? StringLatin1.lines(value, >>> maxLeading, maxTrailing) >>> ?: StringUTF16.lines(value, maxLeading, maxTrailing); >>> ? ??return?stream; >>> } >>> >>> /** >>> ?* Returns a stream of substrings extracted from this string >>> ?* partitioned by line terminators. >>> ?*?

>>> ?* Line terminators recognized are line feed >>> ?* {@code?"\n"} ({@code?U+000A}), >>> ?* carriage return >>> ?* {@code?"\r"} ({@code?U+000D}) >>> ?* and a carriage return followed immediately by a line feed >>> ?* {@code?"\r\n"} ({@code?U+000D U+000A}). >>> ?*?

>>> ?* The stream returned by this method contains each line of >>> ?* this string that is terminated by a line terminator except that >>> ?* the last line can either be terminated by a line terminator or the >>> ?* end of the string. >>> ?* The lines in the stream are in the order in which >>> ?* they occur in this string and do not include the line terminators >>> ?* partitioning the lines. >>> ?* >>> ?*?@implNote?This method provides better performance than >>> ?* ? ? ? ? ? split("\R") by supplying elements lazily and >>> ?* ? ? ? ? ? by faster search of new line terminators. >>> ?* >>> ?*?@return ?the stream of strings extracted from this string >>> ?* ? ? ? ? ?partitioned by line terminators >>> ?* >>> ?*?@since?11 >>> ?*/ >>> public?Stream lines() { >>> ? ??return?lines(0,?0); >>> } >>> >>>> On Jun 7, 2018, at 2:49 PM, Guy Steele >>> > wrote: >>>> >>>> >>>>> On Jun 7, 2018, at 1:48 PM, Brian Goetz >>>> > wrote: >>>>> >>>>>> >>>>>> Part of the goal was to shorten the name to reduce the annoyance >>>>>> quotient. ?reindent? speaks to me more than ?leftMargin? (starts >>>>>> searching thesaurus.) The combo makes sense too. Then you start >>>>>> thinking in terms of indent is just reindent without the magic. >>>>> >>>>> reindent() is OK by me; its a little longer but it says what it >>>>> means, and still less fussy than trimMargin() or autoMagicReindent(). >>>>> >>>>> undent() is shorter, but sounds more like what happens at an >>>>> auto-body repair shop :) >>>> >>>> Or redent(), which happens a week later. ?:-) >>>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Jun 18 15:52:31 2018 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 18 Jun 2018 11:52:31 -0400 Subject: [RSL] RSL update Message-ID: Time to take stock of where we are with respect to the multi-line aspect of Raw String Literals.? Not surprisingly, this has taken a few iterations to get to a reasonable place.? I think we're in a pretty reasonable place right now. The main challenge is separating "intended" indentation of multi-line strings from the "incidental" indentation that comes from wanting the embedded snippet to look reasonable in the context of the surrounding code / inserted by IDEs.? This, in turn, has prompted an exploration of "what is the user thinking" (always a dangerous question) and a number of proposed tweaks to allow the user greater control over saying "these four spaces may look like incidental indentation, but they are in fact intended." The earlier attempts at controlling these added complexity, but Jim has found a way to get that effect while rolling back the complexity. The main transform we've been designing is what we're now calling `align()` (previously `stripIndent()` or `trimIndent()`), which is to remove all seemingly-incidental horizontal and vertical indentation.? This has been simplified as follows: ?- Now removes all leading and trailing blank lines; ?- Left-justifies remaining text based only on indentation of non-blank lines. The observation that led us here is: if the user wants some extra horizontal indentation, its better to specify this explicitly (say, via an `indent(n)` method) than to rely on significant whitespace of the trailing line.? Similarly, if the user wants extra vertical indentation, that can be also added explicitly.? We think that the current operation now essentially finds Kevin's minimal "rectangular box", and then the user can explicitly add back any extra indentation (horizontal or vertical) that is desired. There are a few reasons why this operation is important: ?- Most users will not want to have to start their code "undented" relative to the Java code, but instead will want it to embed cleanly both horizontally and vertically; ?- As the code is refactored, incidental indentation will change, and this may cause instability in the output.? Users will want a way to get to stable output. Raw string literals already normalize end-of-line characters.? We could describe the transformations that `align()` does as further normalizing horizontal whitespace. In order to make the above argument work, there needs to be an easy way to do relative indentation, which is proposed as: ??? String indent(int n) This indents a multi-line string to the left (negative n) or to the right (positive n) by n whitespace characters.? We can then define, for convenience: ??? String align(int n) { return align().indent(n); } so that users can express normalization + indentation in one go: ??? String s = ` ??????????????? blah blah ???????????????????? blah ?????????????? `.align(4); // normalized, indented 4 chars So there are two indentation mechanisms: relative (indent) and absolute (align).? This covers the waterfront. Assuming we've factored this down to the appropriate primitives, the remaining decision to be made here is: should the language try to auto-align multi-line strings, or is asking users to explicitly use a library method (`string.align()`) better. Arguments in favor of the library approach: ?- Many embedded languages don't care about indentation anyway (HTML, SQL, JSON); ?- The string mangling algorithm is somewhat complicated (though less than it used to be) and subjective, both strikes against pushing it into the language; ?- If auto-alignment doesn't do what the user wants, it may be hard to get back to what the user does want. Arguments in favor of the language approach: ?- Most usages of this feature will want alignment anyway, and having to explicit ask for it feels like noise; ?- Failure to normalize leading whitespace will mean that the indentation of output will be perturbed by ordinary code refactoring (which might lead to instabilities in tests); ?- It is easy to explicitly specify additional horizontal or vertical indentation if desired; normalizing the rest of the time makes results more predictable. Did I miss any? (Note that arguments about constant pool efficiency or runtime efficiency are mostly red herrings; `align()` can be safely folded at compile time in the library approach, and a principled framework for such transformations is in the works.) From gavin.bierman at oracle.com Tue Jun 19 11:21:58 2018 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Tue, 19 Jun 2018 12:21:58 +0100 Subject: JEP325 webpage update Message-ID: <0B7004DE-0202-40DB-8D81-EC11E202E3A0@oracle.com> Just to let you know that we updated the JEP page for Switch expressions to reflect the latest design as shared to this list a little while ago. http://openjdk.java.net/jeps/325 A new draft JLS diff document will be shared soon! Thanks, Gavin -------------- next part -------------- An HTML attachment was scrubbed... URL: From kevinb at google.com Mon Jun 25 21:45:15 2018 From: kevinb at google.com (Kevin Bourrillion) Date: Mon, 25 Jun 2018 14:45:15 -0700 Subject: [RSL] RSL update In-Reply-To: References: Message-ID: Sorry for the delay. I do agree that this is in a reasonable place (and will save my quibbling over the name "align" for later :-)). Here are two more arguments in favor of language-level stripping: 1. Strings inside annotations aren't left out. Whenever an annotation attribute feels like something users may want to use an RSL for, the best we can hope for (if we don't have automatic unindenting) is for the specification of that attribute to say "consumers of this data *really should* call .align() on this" - quite unsatisfying, and we can be sure most annotation specs won't bother. 2. When a parse method throws an exception identifying either character position or line/column number of a parsing error, we would like our IDE to correlate that back to the correct position in the source file where that happened. This is necessarily going to be heuristic in nature no matter what, but any post-processing of the RSL by libraries will make that heuristic that much more dodgy. (aside: we may want to consider an interface that such exceptions can implement, and retrofit java.text.ParseException to implement it.) I don't think I'm being fanciful here; I am definitely seeing that a majority of use cases in our codebase for RSLs are embedding a language which will get parsed and can have parsing errors, and I think shortening the debugging cycle for such errors is virtuous. I am still slow to convince myself that language-based unindenting is absolutely definitely better; however, I do feel like the cited advantages for library-based unindenting are just a bit questionable: On Mon, Jun 18, 2018 at 8:52 AM Brian Goetz wrote: Arguments in favor of the library approach: > - Many embedded languages don't care about indentation anyway (HTML, > SQL, JSON); > This doesn't actually constitute an advantage; it is just saying that one of the advantages on the *other* side can be weighted a little less. > - The string mangling algorithm is somewhat complicated (though less > than it used to be) and subjective, both strikes against pushing it into > the language; > I think that whether it is subjective is subjective. :-) I think it is actually quite simple, straightforward, and defensible. It's a minimal bounding box of the visible text; it is reasonable to assume that what's outside the box was probably never meant to be actual program data. > - If auto-alignment doesn't do what the user wants, it may be hard to > get back to what the user does want. > I'm not sure why this is so. The only "mistake" it can make is removing more space than you meant, but we're saying now that you should restore that space explicitly/programmatically, so.....? Do we have stronger arguments in this column than these? -- Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Jun 26 12:09:35 2018 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 26 Jun 2018 08:09:35 -0400 Subject: [RSL] RSL update In-Reply-To: References: Message-ID: <059fe719-1374-a013-571a-7b4a357012e9@oracle.com> > Here are two more arguments in favor of language-level stripping: > > 1. Strings inside annotations aren't left out. Whenever an annotation > attribute feels like something users may want to use an RSL for, the > best we can hope for (if we don't have automatic unindenting) is for > the specification of that attribute to say "consumers of this data > /really should/?call .align() on this" - quite unsatisfying, and we > can be sure most annotation specs won't bother. This seems like a pretty corner^3 case to me; long strings in annotations are kind of questionable already, multi-line strings in an annotation seem even more so, and in those cases where you absolutely need to be divorced from the incidental indentation, you could just align it yourself correctly, at the cost of uglier indentation (or pull it out into a static var.) > I am still slow to convince myself that language-based unindenting is > absolutely definitely better; however, I do feel like the cited > advantages for library-based unindenting are just a bit questionable: Fair enough, but also -- putting something in the language must meet a higher burden than putting it in a library. If we get the library wrong, we can fix it; if there are more than one reasonable way to do something, we can provide alternate library points for the other cases (.alignDammit()); and users can always create their own libraries for string manipulation if the built-in ones are not right for their purposes.? But, if we put it in the language, this will be the Only Way Forever.? The bar there is high. > Do we have stronger arguments in this column than these? Here's one I worry about.? Will we get the right result with this? String s = ` ? - person: ? ?? - name: /` + name + `/ ?? ? - age: 127`; The second string starts left-justified, so we will strip nothing from it.? So with auto-align, I think we get this: - person: ? - name: /bob/ - age: 127 which is not what we wanted (and YAML won't like this.) (Yes, I know many will say "well, if you idiots just did string interpolation, this wouldn't be an issue", but if string literals and concatenation don't play nicely together, that would be pretty bad.) By leaving it to the user, they are free to put the align where it belongs: String s = (` ? - person: ? ?? - name: /` + name + `/ ?? ? - age: 127`).align(); -------------- next part -------------- An HTML attachment was scrubbed... URL: From kevinb at google.com Tue Jun 26 19:22:21 2018 From: kevinb at google.com (Kevin Bourrillion) Date: Tue, 26 Jun 2018 12:22:21 -0700 Subject: [RSL] RSL update In-Reply-To: <059fe719-1374-a013-571a-7b4a357012e9@oracle.com> References: <059fe719-1374-a013-571a-7b4a357012e9@oracle.com> Message-ID: On Tue, Jun 26, 2018 at 5:09 AM Brian Goetz wrote: > Here are two more arguments in favor of language-level stripping: > > 1. Strings inside annotations aren't left out. Whenever an annotation > attribute feels like something users may want to use an RSL for, the best > we can hope for (if we don't have automatic unindenting) is for the > specification of that attribute to say "consumers of this data *really > should* call .align() on this" - quite unsatisfying, and we can be sure > most annotation specs won't bother. > > This seems like a pretty corner^3 case to me; long strings in annotations > are kind of questionable already, multi-line strings in an annotation seem > even more so, > Huh. I don't personally see a reason to devalue this use case. It occurs tens of thousands of times for us, but I will try to look into them to see whether they are questionable in some way. > and in those cases where you absolutely need to be divorced from the > incidental indentation, you could just align it yourself correctly, at the > cost of uglier indentation (or pull it out into a static var.) > I think these workarounds are fair but are still both a little sad. By leaving it to the user, they are free to put the align where it belongs: > > String s = (` > - person: > - name: /` + name + `/ > - age: 127`).align(); > I have a broader response to this bit, but first I want to drill in just on this workaround a bit. So let's assume we've gone with the library-unindenting option. The workaround exists, but first users will fall into the pit before they realize what went wrong. Is this reason enough that we should change `align` to a static method? That actually makes this problem more or less vanish. That said, I wonder if users are better served by switching to `String.format` whenever possible, anyway. They should .align() the format string instead of the formatted result. It's more foolproof, and they still get the benefit of align() happening at (compile time? load time? whenever the new magic happens). Output will be consistent even if a piece of data unexpectedly contained a newline. I'm roughly expecting to be giving users the advice to avoid mixing RSLs with concatenation altogether. -- Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Jun 26 19:29:16 2018 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 26 Jun 2018 15:29:16 -0400 Subject: [RSL] RSL update In-Reply-To: References: <059fe719-1374-a013-571a-7b4a357012e9@oracle.com> Message-ID: <8AE6D0D3-79CF-4728-A83F-CBEC0CB6A0B7@oracle.com> > The workaround exists, but first users will fall into the pit before they realize what went wrong. Is this reason enough that we should change `align` to a static method? That actually makes this problem more or less vanish. It makes it impossible to forget to use parens, which is good, but I think it will be less pleasant to use, especially with other designed-for-chaining methods being added (indent(), etc.) People like chaining because it specifies the operations in the order they actually happen, which is easier to read. So I would be concerned that this cure has undesirable side effects. > That said, I wonder if users are better served by switching to `String.format` whenever possible, anyway. They should .align() the format string instead of the formatted result. It's more foolproof, and they still get the benefit of align() happening at (compile time? load time? whenever the new magic happens). Output will be consistent even if a piece of data unexpectedly contained a newline. I'm roughly expecting to be giving users the advice to avoid mixing RSLs with concatenation altogether. I think both bits of advice ? use format, and avoid mixing ? are likely to be good style advice regardless. But even if we had interpolation, string literals and string concatenation are fundamental features that should work well together. Having two such fundamental features that can?t be used together is pretty worrying to me. From mark.reinhold at oracle.com Tue Jun 26 22:42:19 2018 From: mark.reinhold at oracle.com (mark.reinhold at oracle.com) Date: Tue, 26 Jun 2018 15:42:19 -0700 Subject: [RSL] RSL update In-Reply-To: <059fe719-1374-a013-571a-7b4a357012e9@oracle.com> References: <059fe719-1374-a013-571a-7b4a357012e9@oracle.com> Message-ID: <20180626154219.21422645@eggemoggin.niobe.net> 2018/6/26 5:09:35 -0700, brian.goetz at oracle.com: > ... > > ... putting something in the language must meet a > higher burden than putting it in a library. If we get the library wrong, > we can fix it; if there are more than one reasonable way to do > something, we can provide alternate library points for the other cases > (.alignDammit()); and users can always create their own libraries for > string manipulation if the built-in ones are not right for their > purposes. But, if we put it in the language, this will be the Only Way > Forever. The bar there is high. I agree with Brian and Jim: This is, really, the key point. We could bake a heuristic into the language after seeing that it works well for an existing large set of use cases. It will still, however, be just a heuristic, and as such it?s going to be wrong for some other use cases and, as we?ve seen, in some of those cases it will be difficult to work around. It?s both clearer and simpler to say that the language will never change the apparent content of a string, raw or otherwise, and leave further manipulation to well-designed libraries. - Mark From gavin.bierman at oracle.com Wed Jun 27 14:22:56 2018 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Wed, 27 Jun 2018 15:22:56 +0100 Subject: Next draft of JEP 325 Switch Expressions available Message-ID: <3AD670BD-C6ED-41AA-8114-61746F0E2306@oracle.com> I have uploaded a draft spec for JEP 325: Switch expressions at http://cr.openjdk.java.net/~gbierman/switch-expressions.html This is a comprehensive rewrite of the previous draft and includes the new `case L ->` switch labels for both switch expressions and statements. Highlights: * Section 14.11 (switch statements) has been rewritten completely. There is now a new subsection on switch blocks. * The grammars for switch statement and switch expression are now identical! * I have changed some terminology: a switch block now contains either switch labeled statement groups (as before) or switch labeled *rules* (instead of clauses). Let me know if you like this new terminology (?rule" instead of ?clause"). * The control statements - break, continue and return - have all been re-specified using a similar style to make it clearer that they are all delimited control operators, and how other constructs delimit their control. * Details of how switch expressions are type checked is now included. This is now quite a long spec - apologies! Thanks, Gavin