multi-line string literals

In the OP, Travis wrote:

There is also the potential suggestion of removing consistent indentation if there is any so as to make formatting of a multi-line string literal look more clean when indented.

Ruby has … oh, on the order of 2^9 different string syntaxes, but none of them address this indentation problem, and it’s a constant complaint. Hacks for it abound.

• • •

In Ruby in the wild, off the top of my head and totally unscientifically, the most widely-used flavors I’ve seen are the heredoc with interpolation and terminator indentation:

    string = <<-EOS
      gone is music
      yet you sing
    EOS

…and just putting newlines inside a double-quoted string:

    string = "
      gone is music
      yet you sing
    "

…probably in that order.

Useful notes on the heredoc variants, typical of Ruby’s “the more syntaxes the merrier!” approach to things:

  Jay Fields' Thoughts: Ruby: Multiline strings - here doc or quotes

Cheers, P

···

On Dec 10, 2015, at 11:02 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 10, 2015, at 6:01 PM, Travis Tilley <ttilley@gmail.com <mailto:ttilley@gmail.com>> wrote:

2) Should escapes like \n be processed always, should they never be processed, or should they be processed by default but disable-able in the syntax?

I would want multi-line string literals to behave as much like normal string literals as possible for consistency. To optimize for developer happiness, to steal the ruby saying, unexpected behavior should be kept to a minimum. If \n works in a normal string literal, it should work in a multi-line string literal... even if you could just hit enter instead.

Yes, I agree that should be the default.

3) What other policy decisions make sense to expose on these literals? Since this will be the “powerful form of string literals”, it makes sense to be the place to put weird knobs that are seldom used but important in various cases.

​I would have to depend entirely on you to inform me of both these knobs and use cases. ​I'd love to hear about them, that's for sure.

The reason I raise the question is that some languages have multiple quote styles (Perl 5 has something like 3 or 4 different string literal styles IIRC?) with different policies. One reason for this is to disable processing of escapes: if you’re using string literals to enter something that uses \ or “ frequently, it can be irritating and ugly to have a lot of \\'s <smb://'s>. In some dialects of inline assembly in C, for example, this can lead to very ugly code.

When introducing a feature like this, I think it would be useful to survey a range of popular languages (and yes, even perl ;-) to understand what facilities they provide and why (i.e. what problems they are solving) and synthesize a good swift design that can solve the same problems with a hopefully simple approach.

I haven’t looked into this area deeply myself, so I can’t give you a recipe to just follow, some research is required :)

My initial goal was the minimal possible work required to decrease the noise of writing large blocks of multi-line text and not have to poke around too much in the lexer and parser code (being completely unfamiliar with the swift codebase, having it just become open source recently).

Understood, but our first goal is to get the best solution, independent of implementation complexity. In this case, I suspect that the hard part in this feature is scoping it out and hashing out the right design with the community. I can’t imagine that we’d end up with a design that is that difficult to implement in any case.

-Chris

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

The reason I raise the question is that some languages have multiple quote
styles (Perl 5 has something like 3 or 4 different string literal styles
IIRC?) with different policies. One reason for this is to disable
processing of escapes: if you’re using string literals to enter something
that uses \ or “ frequently, it can be irritating and ugly to have a lot of
\\'s. In some dialects of inline assembly in C, for example, this can
lead to very ugly code.

​Since the suggestion is python style multi-line string literals, the only
valid terminator would be a triple quote, allowing the use of both " and '
within the literal without having to be escaped (or "" or '', if you're
feeling perverse). As for anything else... I hadn't really thought of it.
​I'd really need more feedback on the mailing list.

When introducing a feature like this, I think it would be useful to survey

a range of popular languages (and yes, even perl ;-) to understand what
facilities they provide and why (i.e. what problems they are solving) and
synthesize a good swift design that can solve the same problems with a
hopefully simple approach.

​Perl and Erlang are unique in that valid code in either language looks
essentially like line noise. I'd rather take inspiration from languages
like ruby, python, and elixir.​

Solving a variety of problems and use cases was not my original intention,
and will probably involve implementing full heredoc style syntax (or more).
If that's where you want the proposal to go, then that's where it will have
to go... but for myself, I don't need anything nearly that complex.​ I only
need multi-line string literals that behave the same as existing string
literals, only without the noise of "foo\n" + "bar\n" + "baz\n" + etc.

Understood, but our first goal is to get the best solution, independent of

implementation complexity. In this case, I suspect that the hard part in
this feature is scoping it out and hashing out the right design with the
community. I can’t imagine that we’d end up with a design that is that
difficult to implement in any case.

​Fair enough. Lets give the idea some time to ferment and community members
time to chime in. ;)

As an aside, I am absolutely loving that Apple is making such an effort to
care about its community. This is something that I wouldn't have expected
just a few years ago and is amazing in my humblest of opinions. <3

​- Travis Tilley

···

On Fri, Dec 11, 2015 at 12:02 AM, Chris Lattner <clattner@apple.com> wrote:

Chris - due to the complexity involved, would it make sense to have
multiple proposals? One syntax need not fulfill the needs of every use
case. My immediate and personal concern is the simplest possible syntax for
multi-line string literals with no behavioral differences from normal
string literals other than 1) the ability to span multiple lines and 2) the
ability to contain unescaped quotes as long as they are not triple quotes.
As additional features, the potential indentation handling previously
discussed in this thread would be a massive bonus that'd make life easier.

Additional proposals for full-on heredoc syntax with both indentation aware
and ignoring syntax (as is typical in other languages) could be made and
implemented separately.

I have no use for an escape-ignoring/escape-unrequiring syntax and would
have to leave that up to others to flesh out and/or implement. This would
make most sense with a heredoc style syntax where the terminator is a very
specific string.

I also have no use for specifying a dialect for a string, which Jordan Rose
suggests is useful for shaders, and have no idea how to implement such a
feature.

The worse that could happen is people sometimes (very rarely) need an
`indent` function to explicitly set and indent level for their multiline
string. Doesn't seem like the worst thing ever.

···

On Thu, 10 Dec 2015 at 18:04 Travis Tilley <ttilley@gmail.com> wrote:

That would be my preference, especially since I can be lazy and re-use the
existing indentation detection code in Lexer.cpp. However, one could argue
that it could be confusing if indentation was intentional so I'd like to
hear more people weigh in on that one, especially core team members.

- Travis Tilley

On Thu, Dec 10, 2015 at 8:46 PM, Jason Dusek <jason.dusek@gmail.com> > wrote:

What do you all think about automatic dedenting of these literals? The
excess whitespace is rarely useful; and usually spawns a dedent function
which comes to decorate all such strings.

What about #?

···

###
string
###

If your string does contain "###" you can simply guard the string with more
# until it fits. Must be symmetrical though. No escaping necessary.

On Sat, Dec 12, 2015 at 1:08 AM, Travis Tilley via swift-evolution < swift-evolution@swift.org> wrote:

Ah. My sincerest apologies for making that assumption then.

Your suggestion doesn't solve my use case, personally. I'm also *hoping*
to officially propose something less complex than heredocs once there's
been enough feedback.

-Travis Tilley

On Fri, Dec 11, 2015 at 5:52 PM, Brent Royal-Gordon < > brent@architechies.com> wrote:

> I'm not entirely sure how to respond to this, but I think some of your
suggestions might go against the goal of having less noise in defining a
multi-line string. It's actually more to type than:
> "this is the first line \n" +
> "this is the second line \n"
> ​...which we can already do.
>
> Your suggestion that each line should end in \n makes me think you're
actually trying to have a bit of fun with me, but I can't really tell and I
really don't want to be rude by making that assumption.

I am being serious. This proposal does require more characters, it’s
true. However, it doesn’t require more *reading*—because the leading
indicators will generally line up, you can ignore them and read everything
to the right, like the “> “ used to demarcate your text above from my
text—and with an editor feature to select several lines and quote them (the
way you can with comments in most editors), it wouldn’t require more
*writing* either. And although it uses more characters, it *also*
unmistakably sets off quoted material from code, comments, other multiline
string literals, and anything else, while being unambiguous about whether
indentation is intended to style the literal or be part of it, without a
bunch of funky obscure modifier characters like "<<-END".

The \n thing was an idle thought being presented for discussion, not a
concrete suggestion, but it was also not a joke. (I realized after sending
it, however, that the trailing newline problem can be solved by simply
having a rule that you strip one trailing newline. If you want your string
to end with a newline, include a sacrificial blank “Foo>” line at the end
of the literal. Some sort of modifier to indicate the trailing newline
behavior is possible too, but see the previous paragraph for my thoughts on
those.)

I’ve used and loved heredocs in Perl and Ruby, but I always understood
that they have significant problems. That experience shaped this proposal.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

​I am with you 100% on that. ​Python has a variety of indentation helpers
and that's something i'd like to avoid. Detecting the indentation of the
first line and removing it from all lines, if consistent (excluding blank
lines), would be nice. Still... Even though I'm not proposing heredocs,
every language with them has two syntaxes for it specifically to make the
indentation issue unambiguous. Waiting for more feedback can't hurt.

​- Travis Tilley

···

On Thu, Dec 10, 2015 at 9:08 PM, Jason Dusek <jason.dusek@gmail.com> wrote:

The worse that could happen is people sometimes (very rarely) need an
`indent` function to explicitly set and indent level for their multiline
string. Doesn't seem like the worst thing ever.

The ruby <<- heredoc syntax, unlike the << heredoc syntax, will strip
indentation if necessary. Technically, it searches for the "least indented
line" in the whole string, and removes exactly that amount from each line.
So yes, the indentation problem -is- solved in ruby (though it might break
entirely if you have empty lines, since the least indented line has no
indentation).

···

On Fri, Dec 11, 2015 at 12:36 AM, Paul Cantrell <cantrell@pobox.com> wrote:

In Ruby in the wild, off the top of my head and totally unscientifically,
the most widely-used flavors I’ve seen are the heredoc with interpolation
and terminator indentation:

    string = <<-EOS
      gone is music
      yet you sing
    EOS

This would probably conflict with Swift's non-official (hopefully official in the future) macro-system (the .gyb files), which makes heavy use of "#".

···

On 12 Dec 2015, at 01:13, Marc Knaup via swift-evolution <swift-evolution@swift.org> wrote:

What about #?

###
string
###

If your string does contain "###" you can simply guard the string with more # until it fits. Must be symmetrical though. No escaping necessary.

On Sat, Dec 12, 2015 at 1:08 AM, Travis Tilley via swift-evolution <swift-evolution@swift.org> wrote:
Ah. My sincerest apologies for making that assumption then.

Your suggestion doesn't solve my use case, personally. I'm also hoping to officially propose something less complex than heredocs once there's been enough feedback.

-Travis Tilley

On Fri, Dec 11, 2015 at 5:52 PM, Brent Royal-Gordon <brent@architechies.com> wrote:
> I'm not entirely sure how to respond to this, but I think some of your suggestions might go against the goal of having less noise in defining a multi-line string. It's actually more to type than:
> "this is the first line \n" +
> "this is the second line \n"
> ​...which we can already do.
>
> Your suggestion that each line should end in \n makes me think you're actually trying to have a bit of fun with me, but I can't really tell and I really don't want to be rude by making that assumption.

I am being serious. This proposal does require more characters, it’s true. However, it doesn’t require more *reading*—because the leading indicators will generally line up, you can ignore them and read everything to the right, like the “> “ used to demarcate your text above from my text—and with an editor feature to select several lines and quote them (the way you can with comments in most editors), it wouldn’t require more *writing* either. And although it uses more characters, it *also* unmistakably sets off quoted material from code, comments, other multiline string literals, and anything else, while being unambiguous about whether indentation is intended to style the literal or be part of it, without a bunch of funky obscure modifier characters like "<<-END".

The \n thing was an idle thought being presented for discussion, not a concrete suggestion, but it was also not a joke. (I realized after sending it, however, that the trailing newline problem can be solved by simply having a rule that you strip one trailing newline. If you want your string to end with a newline, include a sacrificial blank “Foo>” line at the end of the literal. Some sort of modifier to indicate the trailing newline behavior is possible too, but see the previous paragraph for my thoughts on those.)

I’ve used and loved heredocs in Perl and Ruby, but I always understood that they have significant problems. That experience shaped this proposal.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Chris - due to the complexity involved, would it make sense to have multiple proposals? One syntax need not fulfill the needs of every use case.

I’m not sure how to interpret this question. Are you asking whether a proposal should start out simple, then have new things piled on top of it? Or are you suggesting it would be better to have multiple new language features solving different problems?

In this case, my personal preference is to have a really well thought out long term vision for what we are doing in this space, and then subset the implementation to start with the simple pieces. This avoids painting ourselves into a corner. Further, I really hope we can avoid adding N new string literal syntaxes. I see the existing one as the “simple” case, and the multiline case as the “advanced” case which can have knobs put on it for other advanced uses.

-Chris

···

On Dec 10, 2015, at 11:07 PM, Travis Tilley <ttilley@gmail.com> wrote:

My immediate and personal concern is the simplest possible syntax for multi-line string literals with no behavioral differences from normal string literals other than 1) the ability to span multiple lines and 2) the ability to contain unescaped quotes as long as they are not triple quotes. As additional features, the potential indentation handling previously discussed in this thread would be a massive bonus that'd make life easier.

Additional proposals for full-on heredoc syntax with both indentation aware and ignoring syntax (as is typical in other languages) could be made and implemented separately.

I have no use for an escape-ignoring/escape-unrequiring syntax and would have to leave that up to others to flesh out and/or implement. This would make most sense with a heredoc style syntax where the terminator is a very specific string.

I also have no use for specifying a dialect for a string, which Jordan Rose suggests is useful for shaders, and have no idea how to implement such a feature.

The <<- only does that for the EOS terminator, not for every line of the string:

$ irb
2.2.0 :001 > string = <<-EOS
2.2.0 :002"> gone is music
2.2.0 :003"> yet you sing
2.2.0 :004"> EOS
=> " gone is music\n yet you sing\n"

(Ruby 2.2)

···

On Dec 10, 2015, at 11:45 PM, Travis Tilley <ttilley@gmail.com> wrote:

The ruby <<- heredoc syntax, unlike the << heredoc syntax, will strip indentation if necessary. Technically, it searches for the "least indented line" in the whole string, and removes exactly that amount from each line. So yes, the indentation problem -is- solved in ruby (though it might break entirely if you have empty lines, since the least indented line has no indentation).

On Fri, Dec 11, 2015 at 12:36 AM, Paul Cantrell <cantrell@pobox.com <mailto:cantrell@pobox.com>> wrote:
In Ruby in the wild, off the top of my head and totally unscientifically, the most widely-used flavors I’ve seen are the heredoc with interpolation and terminator indentation:

    string = <<-EOS
      gone is music
      yet you sing
    EOS

The ruby <<- heredoc syntax, unlike the << heredoc syntax, will strip

indentation if necessary. Technically, it searches for the "least indented
line" in the whole string, and removes exactly that amount from each line.
So yes, the indentation problem -is- solved in ruby (though it might break
entirely if you have empty lines, since the least indented line has no
indentation).

To my mind, the rules should be:

   1. The indentation level is set from the least indented line that is not
   the first line and is not empty.
   2. A leading empty line is removed.
   3. The leading line, if there is any text in it, is not subject to
   de-indentation.

I genuinely believe these three rules taken together address all the errors
and infelicities to which triple quotes and HEREDOCs subject us. Here are
some examples:

text = """
    Some

  Features
    Are
    Discussed
"""# From (1): The indentation is taken from the third line below
`text`, so it's 2.# From (2): First line is: "\n" so it is removed.#

From (3): No effect.

text = """ Some

          Features
            Are
            Discussed
"""# From (1): The indentation is taken again from the line reading
"Features". Here it is 10.# From (2): No effect.# From (3): The
leading whitespace in ` Some` is preserved.

Do you all think these rules pass muster?

A fourth rule — one which seems advisable but also less necessary than the
others — is that a string constructed in this way always ends with a
newline. It is a rule that perhaps leads to surprises and inconsistencies.

Best Regards,

Jason

···

On Thu, 10 Dec 2015 at 21:45, Travis Tilley via swift-evolution < swift-evolution@swift.org> wrote:

Whops sorry I got the symbols mixed up, Swift's macro system uses "%", but the preprocessor uses "#". By using "#" as a delimiter, the lexer would have to be adjusted quite a bit to work for both literals and the preprocessor.

···

On 12 Dec 2015, at 02:09, Kametrixom Tikara via swift-evolution <swift-evolution@swift.org> wrote:

This would probably conflict with Swift's non-official (hopefully official in the future) macro-system (the .gyb files), which makes heavy use of "#".

On 12 Dec 2015, at 01:13, Marc Knaup via swift-evolution <swift-evolution@swift.org> wrote:

What about #?

###
string
###

If your string does contain "###" you can simply guard the string with more # until it fits. Must be symmetrical though. No escaping necessary.

On Sat, Dec 12, 2015 at 1:08 AM, Travis Tilley via swift-evolution <swift-evolution@swift.org> wrote:
Ah. My sincerest apologies for making that assumption then.

Your suggestion doesn't solve my use case, personally. I'm also hoping to officially propose something less complex than heredocs once there's been enough feedback.

-Travis Tilley

On Fri, Dec 11, 2015 at 5:52 PM, Brent Royal-Gordon <brent@architechies.com> wrote:
> I'm not entirely sure how to respond to this, but I think some of your suggestions might go against the goal of having less noise in defining a multi-line string. It's actually more to type than:
> "this is the first line \n" +
> "this is the second line \n"
> ​...which we can already do.
>
> Your suggestion that each line should end in \n makes me think you're actually trying to have a bit of fun with me, but I can't really tell and I really don't want to be rude by making that assumption.

I am being serious. This proposal does require more characters, it’s true. However, it doesn’t require more *reading*—because the leading indicators will generally line up, you can ignore them and read everything to the right, like the “> “ used to demarcate your text above from my text—and with an editor feature to select several lines and quote them (the way you can with comments in most editors), it wouldn’t require more *writing* either. And although it uses more characters, it *also* unmistakably sets off quoted material from code, comments, other multiline string literals, and anything else, while being unambiguous about whether indentation is intended to style the literal or be part of it, without a bunch of funky obscure modifier characters like "<<-END".

The \n thing was an idle thought being presented for discussion, not a concrete suggestion, but it was also not a joke. (I realized after sending it, however, that the trailing newline problem can be solved by simply having a rule that you strip one trailing newline. If you want your string to end with a newline, include a sacrificial blank “Foo>” line at the end of the literal. Some sort of modifier to indicate the trailing newline behavior is possible too, but see the previous paragraph for my thoughts on those.)

I’ve used and loved heredocs in Perl and Ruby, but I always understood that they have significant problems. That experience shaped this proposal.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Catching up with the rest of this thread, here’s what I’d suggest:

- Please don’t extend simple “foo” strings to multiple lines.
- The ``` syntax is actually pretty interesting, I think that exploring it makes sense. “”” doesn’t seem problematic to me though.
- Please consider ways that the string can have extensible options applied to it. I haven’t thought much about this space, but the "String literal suffixes for defining types” has some interesting ideas (though using prefixes instead of suffixes seems appealing as was pointed out in some email).
- I completely agree with Brent’s observation that we shouldn’t optimize for multi-line literals embedded into the middle of some other large expression.

The “configuration” aspect of this feature has come up several times. It seems clear that the multi line literal has some obvious strong defaults: leading whitespace should be stripped, and escapes should be processed (including interpolation). That said, being able to disable these independent of each other is important, and there are lots of other behaviors that can be considered as well. I consider it a good thing for these behaviors to be explicit in the code.

As a strawman proposal (i.e. don’t take it seriously) to illustrate what I mean, you could use attributes for this, e.g. something like:

let foo = @disable_escape_processing ```
blah
blah
blah```

-Chris

···

On Dec 14, 2015, at 12:35 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 10, 2015, at 11:07 PM, Travis Tilley <ttilley@gmail.com <mailto:ttilley@gmail.com>> wrote:

Chris - due to the complexity involved, would it make sense to have multiple proposals? One syntax need not fulfill the needs of every use case.

I’m not sure how to interpret this question. Are you asking whether a proposal should start out simple, then have new things piled on top of it? Or are you suggesting it would be better to have multiple new language features solving different problems?

In this case, my personal preference is to have a really well thought out long term vision for what we are doing in this space, and then subset the implementation to start with the simple pieces. This avoids painting ourselves into a corner. Further, I really hope we can avoid adding N new string literal syntaxes. I see the existing one as the “simple” case, and the multiline case as the “advanced” case which can have knobs put on it for other advanced uses.

I think I’d rather treat the multiline literal as a fenced block.

let text =
    """
    The position of the first " is where the indentation is considered the left-edge.
    
        This line is indented four spaces.

    If I want a newline at the end of the string, I simply put one.

    """

This creates very easy rules to understand:

The position of the opening """ dictates the left-edge for indentation purposes.
It’s invalid to have any text on the lines that contain the start and stop tokens: """
The start and stop tokens must be left-edge aligned.
Text cannot be in a column that preceding the column the tokens start on, unless it is only whitespace.

More examples:

let text =
    """ Invalid: This is not allowed.
    """

let text = """ Invalid; edges are not aligned.
    
    """

let text = """
    Invalid: Text cannot start before the """ tokens.
    
           """

let text = """
           This is ok.
    
           """

let text = """
           Escaped characters are interpreted as normal: \n\n
           There will be two newlines above this string when rendered.
    
           """

-David

···

On Dec 10, 2015, at 10:33 PM, Travis Tilley via swift-evolution <swift-evolution@swift.org> wrote:

I had been operating on the assumption that a leading blank line would be stripped if present, since the syntax in code would look much cleaner, but a trailing line would not since it would likely be intentional. I guess that's another detail that would need to be fleshed out if we decide to go with triple quote syntax (which, at this point, isn't a given... chris lattner brings up some very good points that might require more involved, potentially heredoc-like, syntax to solve).

Your fourth rule, however, I don't agree with at all. It should be obvious from where you place the final quotes whether or not the string includes a trailing newline. Just like in ruby, I believe in and value the principle of least surprize.

- Travis Tilley

On Fri, Dec 11, 2015 at 1:04 AM, Jason Dusek <jason.dusek@gmail.com <mailto:jason.dusek@gmail.com>> wrote:
On Thu, 10 Dec 2015 at 21:45, Travis Tilley via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

The ruby <<- heredoc syntax, unlike the << heredoc syntax, will strip indentation if necessary. Technically, it searches for the "least indented line" in the whole string, and removes exactly that amount from each line. So yes, the indentation problem -is- solved in ruby (though it might break entirely if you have empty lines, since the least indented line has no indentation).

To my mind, the rules should be:

The indentation level is set from the least indented line that is not the first line and is not empty.
A leading empty line is removed.
The leading line, if there is any text in it, is not subject to de-indentation.
I genuinely believe these three rules taken together address all the errors and infelicities to which triple quotes and HEREDOCs subject us. Here are some examples:

text = """
    Some

  Features
    Are
    Discussed
"""
# From (1): The indentation is taken from the third line below `text`, so it's 2.
# From (2): First line is: "\n" so it is removed.
# From (3): No effect.

text = """ Some

          Features
            Are
            Discussed
"""
# From (1): The indentation is taken again from the line reading "Features". Here it is 10.
# From (2): No effect.
# From (3): The leading whitespace in ` Some` is preserved.
Do you all think these rules pass muster?

A fourth rule — one which seems advisable but also less necessary than the others — is that a string constructed in this way always ends with a newline. It is a rule that perhaps leads to surprises and inconsistencies.

Best Regards,

Jason

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I had been operating on the assumption that a leading blank line would be
stripped if present, since the syntax in code would look much cleaner, but
a trailing line would not since it would likely be intentional. I guess
that's another detail that would need to be fleshed out if we decide to go
with triple quote syntax (which, at this point, isn't a given... chris
lattner brings up some very good points that might require more involved,
potentially heredoc-like, syntax to solve).

Your fourth rule, however, I don't agree with at all. It should be obvious
from where you place the final quotes whether or not the string includes a
trailing newline. Just like in ruby, I believe in and value the principle
of least surprize.

- Travis Tilley

···

On Fri, Dec 11, 2015 at 1:04 AM, Jason Dusek <jason.dusek@gmail.com> wrote:

On Thu, 10 Dec 2015 at 21:45, Travis Tilley via swift-evolution < > swift-evolution@swift.org> wrote:

The ruby <<- heredoc syntax, unlike the << heredoc syntax, will strip

indentation if necessary. Technically, it searches for the "least indented
line" in the whole string, and removes exactly that amount from each line.
So yes, the indentation problem -is- solved in ruby (though it might break
entirely if you have empty lines, since the least indented line has no
indentation).

To my mind, the rules should be:

   1. The indentation level is set from the least indented line that is
   not the first line and is not empty.
   2. A leading empty line is removed.
   3. The leading line, if there is any text in it, is not subject to
   de-indentation.

I genuinely believe these three rules taken together address all the
errors and infelicities to which triple quotes and HEREDOCs subject us.
Here are some examples:

text = """
    Some

  Features
    Are
    Discussed
"""# From (1): The indentation is taken from the third line below `text`, so it's 2.# From (2): First line is: "\n" so it is removed.# From (3): No effect.

text = """ Some

          Features
            Are
            Discussed
"""# From (1): The indentation is taken again from the line reading "Features". Here it is 10.# From (2): No effect.# From (3): The leading whitespace in ` Some` is preserved.

Do you all think these rules pass muster?

A fourth rule — one which seems advisable but also less necessary than the
others — is that a string constructed in this way always ends with a
newline. It is a rule that perhaps leads to surprises and inconsistencies.

Best Regards,

Jason

Yeah, I can't say I am totally committed to the fourth one.

···

On Thu, 10 Dec 2015 at 22:34 Travis Tilley <ttilley@gmail.com> wrote:

I had been operating on the assumption that a leading blank line would be
stripped if present, since the syntax in code would look much cleaner, but
a trailing line would not since it would likely be intentional. I guess
that's another detail that would need to be fleshed out if we decide to go
with triple quote syntax (which, at this point, isn't a given... chris
lattner brings up some very good points that might require more involved,
potentially heredoc-like, syntax to solve).

Your fourth rule, however, I don't agree with at all. It should be obvious
from where you place the final quotes whether or not the string includes a
trailing newline. Just like in ruby, I believe in and value the principle
of least surprize.

- Travis Tilley

On Fri, Dec 11, 2015 at 1:04 AM, Jason Dusek <jason.dusek@gmail.com> > wrote:

On Thu, 10 Dec 2015 at 21:45, Travis Tilley via swift-evolution < >> swift-evolution@swift.org> wrote:

The ruby <<- heredoc syntax, unlike the << heredoc syntax, will strip

indentation if necessary. Technically, it searches for the "least indented
line" in the whole string, and removes exactly that amount from each line.
So yes, the indentation problem -is- solved in ruby (though it might break
entirely if you have empty lines, since the least indented line has no
indentation).

To my mind, the rules should be:

   1. The indentation level is set from the least indented line that is
   not the first line and is not empty.
   2. A leading empty line is removed.
   3. The leading line, if there is any text in it, is not subject to
   de-indentation.

I genuinely believe these three rules taken together address all the
errors and infelicities to which triple quotes and HEREDOCs subject us.
Here are some examples:

text = """
    Some

  Features
    Are
    Discussed
"""# From (1): The indentation is taken from the third line below `text`, so it's 2.# From (2): First line is: "\n" so it is removed.# From (3): No effect.

text = """ Some

          Features
            Are
            Discussed
"""# From (1): The indentation is taken again from the line reading "Features". Here it is 10.# From (2): No effect.# From (3): The leading whitespace in ` Some` is preserved.

Do you all think these rules pass muster?

A fourth rule — one which seems advisable but also less necessary than
the others — is that a string constructed in this way always ends with a
newline. It is a rule that perhaps leads to surprises and inconsistencies.

Best Regards,

Jason

This example will break easily when tabs are used for indentation or when
using refactoring tools to rename the variable:

let text = """
           This is ok.

           """

Rather I'd suggest that when there is no newline before the opening
triple-quote then the indentation is ignored completely, like in the
example from Drew Crawford:

let sampleJSON = """
{
  "foo": "bar",
  "baz": "bap\nbap"
}
"""

This is great for cases where you don't need to care about indentation or
where you want to copy&paste something without re-indenting it.
It also works fine no matter if the developer uses tabs or spaces for
indentation.

···

On Fri, Dec 11, 2015 at 10:26 AM, David Owens II via swift-evolution < swift-evolution@swift.org> wrote:

I think I’d rather treat the multiline literal as a fenced block.

let text =
    """
    The position of the first " is where the indentation is considered
the left-edge.

        This line is indented four spaces.

    If I want a newline at the end of the string, I simply put one.

    """

This creates very easy rules to understand:

   1. The position of the opening """ dictates the left-edge for
   indentation purposes.
   2. It’s invalid to have any text on the lines that contain the start
   and stop tokens: """
   3. The start and stop tokens must be left-edge aligned.
   4. Text cannot be in a column that preceding the column the tokens
   start on, unless it is only whitespace.

More examples:

let text =
    """ Invalid: This is not allowed.
    """

let text = """ Invalid; edges are not aligned.

    """

let text = """
    Invalid: Text cannot start before the """ tokens.

           """

let text = """
           This is ok.

           """

let text = """
           Escaped characters are interpreted as normal: \n\n
           There will be two newlines above this string when rendered.

           """

-David

On Dec 10, 2015, at 10:33 PM, Travis Tilley via swift-evolution < > swift-evolution@swift.org> wrote:

I had been operating on the assumption that a leading blank line would be
stripped if present, since the syntax in code would look much cleaner, but
a trailing line would not since it would likely be intentional. I guess
that's another detail that would need to be fleshed out if we decide to go
with triple quote syntax (which, at this point, isn't a given... chris
lattner brings up some very good points that might require more involved,
potentially heredoc-like, syntax to solve).

Your fourth rule, however, I don't agree with at all. It should be obvious
from where you place the final quotes whether or not the string includes a
trailing newline. Just like in ruby, I believe in and value the principle
of least surprize.

- Travis Tilley

On Fri, Dec 11, 2015 at 1:04 AM, Jason Dusek <jason.dusek@gmail.com> > wrote:

On Thu, 10 Dec 2015 at 21:45, Travis Tilley via swift-evolution < >> swift-evolution@swift.org> wrote:

The ruby <<- heredoc syntax, unlike the << heredoc syntax, will strip

indentation if necessary. Technically, it searches for the "least indented
line" in the whole string, and removes exactly that amount from each line.
So yes, the indentation problem -is- solved in ruby (though it might break
entirely if you have empty lines, since the least indented line has no
indentation).

To my mind, the rules should be:

   1. The indentation level is set from the least indented line that is
   not the first line and is not empty.
   2. A leading empty line is removed.
   3. The leading line, if there is any text in it, is not subject to
   de-indentation.

I genuinely believe these three rules taken together address all the
errors and infelicities to which triple quotes and HEREDOCs subject us.
Here are some examples:

text = """
    Some

  Features
    Are
    Discussed
"""# From (1): The indentation is taken from the third line below `text`, so it's 2.# From (2): First line is: "\n" so it is removed.# From (3): No effect.

text = """ Some

          Features
            Are
            Discussed
"""# From (1): The indentation is taken again from the line reading "Features". Here it is 10.# From (2): No effect.# From (3): The leading whitespace in ` Some` is preserved.

Do you all think these rules pass muster?

A fourth rule — one which seems advisable but also less necessary than
the others — is that a string constructed in this way always ends with a
newline. It is a rule that perhaps leads to surprises and inconsistencies.

Best Regards,

Jason

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

My 5 cents:

+1 for indentation removal as the default (and maybe the only option). This is really the only common case.

+1 for removing all indentation based on either the first or the least indented line;
-1 for using the position of """ to indicate the amount of indentation to remove — nothing is more stupid than forcing to write an extra newline before """.

+1 for """, it communicates the fact that this is a regular string, just a bit longer than other strings;
-1 for ```, I believe that backticks communicate a bigger difference than there is.

+1 for not complicating it further than that.

+100 for the feature, overall.

A.

What about the following proposal, I’m afraid I don’t know if it’s possible to implement, but it really represents everything that I would like to see in a multiline String solution because it has no special syntax and the results are extremely straight forward and non-magical.

let x =
"This is a proposal for a multiline literal String in Swift. This syntax solves a number of problems that
"are common in other language's implementations of multiline Strings. This syntax is meant to be a
"a generalization of regular Swift literal Strings, whereby a String is considered to begin with an open quote
"and continue indefinitely until and including the end of the line (newline character),
"or the String is closed with an ending quote.
"
"Firstly, indentation is now very clear and explicit. It is easy to see what the resulting string will be.
" This is one level of indentation.
" This is two levels.
"
"Secondly, there is no need for newline character processesing since it is well defined what newline behavior
"should be.
"
"If a newline should be present in the code, but not in the resulting String it can be escaped with '\\' \
" like so.
"
"Alternatively, perhaps that behavior could be left out and still accomplished by appending Strings in the
" normal way with + or implicitly concatonated by the complier. Like so:
" This is a long single line literal String. This is a long single line literal String. This is a long single"
"line literal String."
"
"Thirdly, the indent level of these strings is decoupled from the indent level of the code, since there is a
        "well defined starting point for the String on each line.
    " Thus you can indent the code and the string independently.
"
"Lastly, I don't actually know if this is even possible to implement. I don't know if these creates ambiguities
"for the compiler, but it doesn't seem like it does at first glance.

This would require that adjacent Strings are automatically appended to each other by the compiler, (e.g. let x = “blah” “blah”, would be valid and x would equal “blahblah”. I don’t know how others would feel about something like this, but I’ve always wanted this behavior in multiline Strings. Perhaps I’ve forgotten some edge cases?

Tyler

···

On Dec 14, 2015, at 12:47 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 14, 2015, at 12:35 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Dec 10, 2015, at 11:07 PM, Travis Tilley <ttilley@gmail.com <mailto:ttilley@gmail.com>> wrote:

Chris - due to the complexity involved, would it make sense to have multiple proposals? One syntax need not fulfill the needs of every use case.

I’m not sure how to interpret this question. Are you asking whether a proposal should start out simple, then have new things piled on top of it? Or are you suggesting it would be better to have multiple new language features solving different problems?

In this case, my personal preference is to have a really well thought out long term vision for what we are doing in this space, and then subset the implementation to start with the simple pieces. This avoids painting ourselves into a corner. Further, I really hope we can avoid adding N new string literal syntaxes. I see the existing one as the “simple” case, and the multiline case as the “advanced” case which can have knobs put on it for other advanced uses.

Catching up with the rest of this thread, here’s what I’d suggest:

- Please don’t extend simple “foo” strings to multiple lines.
- The ``` syntax is actually pretty interesting, I think that exploring it makes sense. “”” doesn’t seem problematic to me though.
- Please consider ways that the string can have extensible options applied to it. I haven’t thought much about this space, but the "String literal suffixes for defining types” has some interesting ideas (though using prefixes instead of suffixes seems appealing as was pointed out in some email).
- I completely agree with Brent’s observation that we shouldn’t optimize for multi-line literals embedded into the middle of some other large expression.

The “configuration” aspect of this feature has come up several times. It seems clear that the multi line literal has some obvious strong defaults: leading whitespace should be stripped, and escapes should be processed (including interpolation). That said, being able to disable these independent of each other is important, and there are lots of other behaviors that can be considered as well. I consider it a good thing for these behaviors to be explicit in the code.

As a strawman proposal (i.e. don’t take it seriously) to illustrate what I mean, you could use attributes for this, e.g. something like:

let foo = @disable_escape_processing ```
blah
blah
blah```

-Chris

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I was thinking of keeping it really simple and having just a few main rules.

1) using " means that the string contents are escaped
2) using ' means that the string contents are unescaped/raw
3) using """ or ''' means that it's a multi-line string and indentation
erasure rules are in effect
4) indentation erasure is from the least indented line (from start of line,
not start of quote)
5) the first line, if it contains only a newline, is removed entirely (this
lets you just start your text on the next line)

I'm wibbly wobbly about the last line containing only a newline. I'm not
sure whether to err on the side of caution and assume it's intentional, or
remove it as well. At the moment I'm leaning toward assuming it's
intentional.

I'm also not entirely sure what to do in the case of mixed indentation. I
could absolutely see the leading indentation being tabs (with the editor
displaying them as equivalent to 4 spaces), but the slight indentation of
one to three characters being spaces.

Here is the SQL example for reference to show what I mean:

func findMentions(account: String) -> Array<String> {
    let db = databaseFactory().findDatabase()
    let q = '''SELECT array_agg(mentioner.id)
                 FROM account
                 JOIN mention ON (account.id = mentioned)
                 JOIN account AS mentioner ON (mentioner.id = mentioner)
                WHERE account.handle = :1
                ORDER BY timestamp DESC
                LIMIT 1'''

    return db.query(q).parameterize(account).run()
}

​- Travis Tilley​