String reboot - (1a) incidental whitespace
Jim Laskey
james.laskey at oracle.com
Wed Apr 17 14:22:24 UTC 2019
(inline and at the bottom)
> On Apr 16, 2019, at 8:03 PM, Liam Miller-Cushon <cushon at google.com> wrote:
>
> On Wed, Apr 10, 2019 at 8:25 AM Jim Laskey <james.laskey at oracle.com <mailto:james.laskey at oracle.com>> wrote:
> Don’t peek yet. Stop and comment first.
>
> Here's a variation on the narrative you provided. This is more thinking aloud than a proposal I'm advocating for, but I think it's a potentially interesting point in the design space.
>
> Idea: multi-line strings should be formatted like other expressions, rather than a block-like construct (this differs from the 'fat delimiter pattern' in the original message), i.e.:
>
> String a = """
> ...
> """; // +8 expression continuation indent
>
> Policy: both delimiters must be on a separate line from the contents of the string. This means we can't have 'multi-line' strings that do not span multiple lines of source code.
Stephen also suggests this. While not unreasonable, it's more of a convention than a rule. We need a strong argument for why to not allow content on the same lines.
>
> Since the closing delimiter's indentation is independent of the position of the opening delimiter, and cannot be on the same line as the string contents, this opens the door to basing the relative indentation off the closing delimiter. (It also avoids needing information from the scanner to manage indentation.)
This has been mentioned before and is "how Swift does it". I tend to favour this approach and what String::align did until CSR discussions.
>
> > What control knobs do we have, that we could assign meaning to, that would let the user choose either way?
>
> The position of the closing delimiter.
>
> > Do we allow content on the same lines as the delimiters?
>
> No
>
> > How do we interpret auto-alignment on single-line strings? Strip?
>
> Single-line strings cannot use `"""`, since we require the delimiters to be on their own line.
>
> > Should we always add a final newline?
> > Should we strip blanks lines? Only on the first and last? All leading and trailing?
> > Should we right strip lines?
>
> Maybe (read on for some discussion of trailing newlines). For the most part the other choices don't affect the following examples.
>
> Examples:
>
> String a = """
> +--------+
> | text |
> +--------+
> """; // first characters in first column?
>
> Actual:
>
> +--------+\n
> | text |\n
> +--------+
>
> String b = """
> +--------+
> | text |
> +--------+
> """; // first characters in first column or indented four spaces?
>
> Actual: +4 indentation relative to closing delimiter:
>
> +--------+\n
> | text |\n
> +--------+
>
> String c = """
> +--------+
> | text |
> +--------+
> """; // first characters in first column or indented several?
>
> Actual: indented several, relative to closing delimiter:
>
> +--------+\n
> | text |\n
> +--------+
>
> String d = """
> +--------+
> | text |
> +--------+
> """; // first characters in first column or indented four?
>
> Actual: +4 indentation relative to closing delimiter:
>
> +--------+\n
> | text |\n
> +--------+
>
> String e =
> """
> +--------+
> | text |
> +--------+
> """; // heredoc?
>
> Actual:
>
> +--------+\n
> | text |\n
> +--------+
>
> String f = """
>
>
> +--------+
> | text |
> +--------+
>
>
> """; // one or all leading or trailing blank lines stripped?
>
> Actual:
>
> \n
> \n
> +--------+\n
> | text |\n
> +--------+\n
> \n
>
>
> Examples g, h, and i are disallowed, since delimiters must be on their own line.
>
> For j, since delimiters must be on their own line, we'd need something like:
>
> String j = """
> public static void
> """
> + " " + name
> + """
> (String... args) {
> System.out.println(String.join(args));
> }
> """;
>
> Using a multi-line string for "public static void" is unnecessary, but I kept that to illustrate what concatenation looks like with multi-line strings. This example suggests we'd usually prefer `String.format` to concatenating multi-line strings under this approach.
>
> Conclusions:
>
> Requiring delimiters to be on their own line rules out some potentially surprising edge-cases, and allows indentation management to work without special knowledge from the scanner. It also provides a convenient opt-out mechanism if leading indentation is desired.
>
> One disadvantage is the handling of the trailing newline. Requiring the closing delimiter to be on its own line means there's always a trailing newline in source. If we want to allow expressing multi-line strings that don't have a trailing newline we could automatically trim one trailing newline character, but then it would be necessary to leave an extra blank line after multi-line strings in cases where a trailing newline is actually desired. Example:
>
> String message = """
> hello
> world
>
> """;
>
> Actual:
>
> hello\n
> world\n
>
Not sure that having or not having a new line at the end really matters much. Both String::split('\n') and String::lines() are agnostic whether the last \n is present. Of course, it's easier to add than to remove, so not having it might be preferable.
But, that is all conditional on the "both delimiters must be on a separate line from the contents of the string" rule. As stated, this is more of a convention than a syntax rule.
Let's go back to having close delimiter influencing indentation and the original close delimiter influencing presence of trailing \n. Can we have both? Do they conflict? If so, how do we counteract the default action?
So the default alignment would play out as this;
String s = """
line 1
line 2
""";
Actual:
line 1\n
line 2\n
Let's look at the two contrary examples.
// We want to indent 4 but no \n at end
String noNewline = """
line 1
line 2
""";
Actual fail:
line 1\n
line 2\n
In this case, we get the indentation we want, but get a final \n we don't want.
A workaround here is
String noNewline = """
line 1
line 2""". indent(4);
Actual:
line 1\n
line 2
Next case.
// We want no \n at the end but we want to indent 4
String wrongIndent = """
line 1
line 2""";
Actual fails:
line 1\n
line 2
In this case, we drop the \n we want to drop, but get the wrong indentation.
Interestingly, the workaround here is the same
String wrongIndent = """
line 1
line 2""". indent(4);
Actual:
line 1\n
line 2
So we can have both close delimiter influences, with workarounds for the contrary cases.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20190417/687e4d75/attachment-0001.html>
More information about the amber-spec-experts
mailing list