I’ve update my gist to reflect that now: 
https://gist.github.com/DevAndArtist/dae76d4e3d4e49b1fab22ef7e86a87a9

Simple ‘multi-line string literal’ model

Core features:

Omitting of (most) backslashes for ".
Altering the string with implicit new line injection at the end of the line.
Sting interpolation (trivial in terms of consistency and functionality).
Consequences of #1:

To omit escaping the quote character, the delimiter characters for the 
multi-line string literal will be tripled quotes """, also similar to other 
programming languages.

When a standard string literal contains at least 5 quotes, then the usage of a 
multi-line string literal can be shorter.

"<a href=\"\(url)\" id=\"link\(i)\" class=\"link\">"    // With escapes
"""<a href="\(url)" id="link\(i)" class="link">"""      // With tripled literals
Consequences of #2:

To fully support this feature, we need to compromise the design for simplicity 
and intuitivity.

This feature needs precision for leading and trailing whitespaces.

Alternatively one would need a way to disable new line injection to also 
support code formatting.

Two ways of writing a multi-line string literal:

Single line version """abc""" is trivial and already was shown above.

The multi-line version comes with a few compromises for simplicity of rules:

"""   // DS (delimiter start)
foo   // s0
foo   // s1
foo   // s2
"""   // DE (delimiter end)
The string content is always written between the lines DS and DE (delimiter 
lines).
That means that the following snippets are not allowed:

// Banned option 1:
"""foo
   foo
   """  
    
// Banned option 2:  
"""foo
   foo"""  
    
// Banned option 3:
"""
foo
foo"""  
To not to go the continuation quotes path, the left (or leading) precision is 
handled by the closing delimiter (1. compromise). The closing delimiter is also 
responsible for the indent algorithm, which will calculate the stripping prefix 
in line DE and apply stripping to lines s0 to sn.

Right (or trailing) precision of each line from s0 to sn (notice n equals 2 in 
the example above) is handled by a backslash character (2. compromise).

The right precision comes at a price of losing the implicit new line injection, 
however this was also a requested feature (3. compromise). That means that the 
backslash can serve two jobs simultaneously.

New line injection happens only on lines s0 to s(n - 1) (4. and last compromise 
of the design). The last line sn (or s2 above) does not inject a new line into 
the final string. This implies that in this line a backslash character handles 
only right precision, or one could say it’s reduced for one functionality.

The following multi-line string literal

print("""
  foo
  foo
  """)
will produce the string “foo\nfoo” and only print:

foo
foo
Important:

Because whitespace is important to these examples, it is explicitly indicated: 
· is a space, ⇥ is a tab, and ↵ is a newline.

Leading/trailing precision and indent (1. and 2. compromise):

// Nothing to strip in this example (no indent).
let str_1 = """↵  
foo↵
"""

// No right precision (no backslash), but presence of whitespace  
// characters will emit a warning.
let str_2 = """↵  
foo··↵
"""
Warning:

warning: line # includes trailing whitespace characters in multi-line string 
literal without the precision `\` character at the end
  foo··↵
     ~~
  Fix-it: Insert "\n\" after the last space character (or only `\` if it's the 
`sn` line)
More examples:

// Simmilar to `str_2`
let str_3 = """↵  
foo····↵
"""

// Line `DE` of the closing delimiter calculates the indent prefix  
// `··` and strips it from `s0` (left precision).
let str_4 = """↵  
··foo↵
··"""

// Line `DE` of the closing delimiter calculates the indent prefix  
// `····` and strips it from `s0` (left precision).
//
// No right precision (no backslash), but presence of whitespace  
// characters will emit a warning.
let str_5 = """↵  
····foo··↵
····"""

// Line `DE` of the closing delimiter calculates the indent prefix  
// `⇥ ⇥ ` and strips it from `s0` (left precision).
//
// Right precision is applied (backslash). In this case the literal
// contains only a single line of content, which happens to be   
// also the last line before `DE` -> backslash only serves precision.
let str_6 = """↵  
⇥ ⇥ foo\↵
⇥ ⇥ """

// Line `DE` of the closing delimiter calculates the indent prefix  
// `·⇥ ·⇥ ` and strips it from `s0` (left precision).
//
// No right precision (no backslash), but presence of whitespace  
// characters will emit a warning.
let str_7 = """↵  
·⇥ ·⇥ foo··↵
·⇥ ·⇥ """

let string_1 = "foo"

str_1 == string_1   // => true
str_2 == string_1   // => false
str_3 == string_1   // => false
str_4 == string_1   // => true
str_5 == string_1   // => false
str_6 == string_1   // => true
str_7 == string_1   // => false
A wrong multi-line string literal, which compiles but emits a warning with a 
fix-it:

let str_8 = """↵  
··foo↵
····"""

str_8 == string_1   // => true
Warning:

warning: missing indentation in multi-line string literal
  ··foo
    ^  
  Fix-it: Insert "··"
The stripping algorithm calculates the prefix indent from the closing delimiter 
line DE and tries to strip it in lines s0 to sn if possible, otherwise each 
line, which could not be handled correctly will emit an individual warning and 
a fix-it.

To align precision of a multi-line string literal with the standard string 
literal, we have to check every content line for trailing whitespace 
characters. If we found any, but there is no \ at the end, a warning will be 
emitted and a fix-it will be provided to add \n\ after the last whitespace 
character for explicit precision, or a \ if the warning happens in the last 
content line sn. This automatically forces the developer to either remove any 
unwanted trailing whitespace characters or be explicit about the trailing 
precision.

An example which will raise such a warning:

"""↵
foo··↵
"""
To fix the issue there are two options:

Use the fix-it: 
"""↵
foo··\↵
"""
Remove the whitespace characters manually: 
"""↵
foo↵
"""
Disabling new line injection (3. compromise):

The examples we’ve used so far had only a single content line, so we couldn’t 
showcase this behavior yet. New lines are only injected into a multi-line 
string if it has at least two content lines.

let str_9 = """↵  
····foo↵
····bar↵
····"""

let str_10 = """↵  
····foo↵
····bar↵
····baz↵
····"""

let string_2 = "foo\nbar"
let string_3 = "foo\nbar\nbaz"

str_9 == string_2  // => true
str_10 == string_3 // => true
To disable new line injection one would need to use the backslash for right 
precision.

let str_11 = """↵  
····foo\↵
····bar↵
····"""

let str_12 = """↵  
····foo\↵
····bar\↵
····baz↵
····"""

str_11 == string_2    // => false
str_12 == string_3    // => false

str_11 == "foorbar"   // => true
str_12 == "foobarbaz" // => true
Remember that the last content line sn does not automatically inject a new line 
into the final string!

New line injection except for the last line (4. compromise):

The standard string literal like "foo" only contains its string content from 
the starting delimiter to the closing delimiter. The discussion on the mailing 
list suggests that the multi-line string literal should also go that route and 
not inject a new line for the last content line sn. str_9 is a good example for 
that behavior.

Now if one would want a new line at the end of the string, there are a few 
options to achieve this:

// Natural way:
let str_13 = """↵  
····foo↵
····bar↵
····↵
····"""

// Remember the last content line does not inject a `\n` character by default
// so there is no need for `\n\` here (but it's possible as well)!
let str_14 = """↵  
····foo↵
····bar\n↵
····"""

let string_4 = "foo\nbar\n"

str_13 == string_4 // => true
str_14 == string_4 // => true
At first glance the behavior in str_13 seems odd and inconsistent, however it 
actually mimics perfectly the natural way of writing text paragraphs and is 
consistent to the standard string literal, which represents only its content 
between the delimiters.

[here is a blank line]↵
text text text text text↵
text text text text text↵
[here is a blank line]
This is easily expressed with the literal model explained above:

let myParagraph = """↵
····↵
····text text text text text↵
····text text text text text↵
····↵
····"""


-- 
Adrian Zubarev
Sent with Airmail

Am 13. April 2017 um 16:39:05, Ricardo Parada ([email protected]) schrieb:

That would be good, I think because it would force everyone to be precise in 
regards to trailing whitespace.  And I don't see that as a bad thing.


On Apr 13, 2017, at 9:54 AM, Adrian Zubarev via swift-evolution 
<[email protected]> wrote:

I was really confused by your last reply. Actually I’ve got a better idea for a 
fix-it. :-)

let str_8 = """↵   
····foo··········↵
····"""
warning: line # includes trailing space characters in multi-line string literal
  ····foo··········
         ~~~~~~~~~~   
  Fix-it: Insert "\n\" (after these space characters)
The fix-it will inset \n\ after all your space characters, so the developer is 
kinda forced to strip them manually to ····foo or let the IDE add \n\ if he 
really needs that precision.

That would work. :)




-- 
Adrian Zubarev
Sent with Airmail

Am 13. April 2017 um 15:46:52, John Holdsworth ([email protected]) 
schrieb:

\n\
would work

On 13 Apr 2017, at 14:44, John Holdsworth <[email protected]> wrote:


I’ve never understood how you mean "explicit backslash". backslash has specific 
roles  
and at the moment it is assigned to meaning standard escapes or "don’t include 
this next
newline in the literal". I can’t see how it could be reassigned to mean 
“include whitespace”
without loosing the option to concatenate lines.

fix-its are beyond my pay grade so that’ll have to wait until Apple looks at 
the implementation!


On 13 Apr 2017, at 14:32, Adrian Zubarev <[email protected]> 
wrote:

A warning that will popup when you included any trailing spaces in a ‘content 
line’ without the explicit backslash could also provide a fix-it to the user to 
remove these spaces. However if you can emit that warning and calculate the 
spaces to remove, than the compiler should be able to swallow these characters 
by default right?





_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to