[swift-evolution] multi-line string literals.

Ted F.A. van Gaalen tedvgiosdev at gmail.com
Sat Apr 30 17:17:44 CDT 2016


Hi Brent,

@Dave - Hi Dave, please see at the end of this email. 

Thanks for your energetic reply, Brent.
First of all, I think there is a place in Swift for “your” and “mine” proposing solutions 
together. I will reply further inline -> 
> On 30.04.2016, at 09:43, Brent Royal-Gordon <brent at architechies.com> wrote:
> 
>> Example 1. The \@ operator: 
>> 
>> 	 // 1.  multi-line string literal with data lines as is. 
>>         // It loads each line (part) up to and including the source-file-line- end:
>>         // you can use all available characters without problems, 
>>         // even \\ and \@  thus allowing you to nest e.g. Swift statements...  
>> 
>>         let xml =                                                    
>>                     \@<?xml version="1.0"?>
>> 	             \@  <catalog>
>> 	             \@    <book id="bk101" empty=“”>      // this is not regarded as a comment.
>> 	             \@       <author>//¯\"_(ツ)_//</author>
>> 	             \@    </book>
>>                     \@  </catalog> 
>> 
>> 
>>   Example 2, The \\ operator: 
>>   // Multi-line string literal with data lines with \n \t etc. respected: 
>> 
>>         var str =
>>                     \\This is line one.\nThis is line two, with a few \t\t\t tabs in it...
>>                     \\                                            
>>                     \\This is line three: there are \(cars)                 // this is a comment.
>>                     \\ waiting in the garage. This is still line three
> 
> There are a lot of reasons why I don't like these.
> 
> The first is simply that I think they're ugly
To me, that is not relevant: 
If something is “ugly”  or not is tied to different and unique 
personal reference, accumulated by experience and 
human instinct and are thus not comparable because no two 
beings are the same. Ergo: This voids a discussion between 
you and me about this subjective aspect “ugliness” 
Still, this aspect should be subordinate to functionality
 (in this case the functionality of a programming language).


> and don't look like they have anything to do with string literals,
You’re right about that:  they are not *string literals* but *data lines*.

 
> but that's solvable. For instance, we could modify my proposal so that, if you were using continuation quotes, you wouldn't have to specify an end quote:
> 
>         let xml =                                                    
>                     "<?xml version="1.0"?>
> 	             "  <catalog>
> 	             "    <book id="bk101" empty=“”>      // this is not regarded as a comment.
> 	             "       <author>//¯\"_(ツ)_//</author>
> 	             "    </book>
>                     "  </catalog> 

Essentially the above is similar to what I propose with “my” data line,
that is, starting each line with a special character/token. But that is where the
similarity ends: It does not offer processing for *both*:
- "as-is" character data
-  character data where escaped characters need to be processed.
   
> 
> So let's set the bikeshed color aside and think about the deeper problem, which is that line-oriented constructs like these are a poor fit for string literals.

> 
> A string literal in Swift is an expression, and the defining feature of expressions is that they can be nested within other expressions.
That is logically correct, (but desirable in all cases? (readability)) however: 
       
As said before, these \@…..  and \\…..   are data lines, not string literals. 
They are not intended to replace string literals.  A slightly different concept.

Data lines are just that and -apart from assignment, that is to be loaded in a String variable or constant- 
not really intended to take further part in expressions. 
however you can still do that, as shown further below.  


> We've been using examples where we simply assign them to variables, but quite often you don't really want to do that—you want to pass it to a function, or use an operator, or do something else with it. With an ending delimiter, that's doable:
> 
> 	let xmlData = 
>                     "<?xml version="1.0"?>
> 	             "  <catalog>
> 	             "    <book id="bk101" empty=“”>      // this is not regarded as a comment.
> 	             "       <author>//¯\"_(ツ)_//</author>
> 	             "    </book>
>                     "  </catalog>".encoded(as: UTF8)
    I do experience this as being “ugly”, but again, this is personal.
> 
> But what if there isn't a delimiter? You would't be able to write the rest of the expression on the same line. In a semicolon-based language, that would merely lead to ugly code:
> 
> 	let xmlData = 
>                     "<?xml version="1.0"?>
> 	             "  <catalog>
> 	             "    <book id="bk101" empty=“”>      // this is not regarded as a comment.
> 	             "       <author>//¯\"_(ツ)_//</author>
> 	             "    </book>
>                     "  </catalog>
> 	             .encoded(as: UTF8);
> 



In “my” case this would be:

   let xml =                                                    
                     \@<?xml version="1.0"?>
	             \@  <catalog>
	             \@    <book id="bk101" empty=“”>      // this is not regarded as a comment.
	             \@       <author>//¯\"_(ツ)_//</author>
	             \@    </book>
                     \@  </catalog> 
                          .encoded(as: UTF8)
  

> But Swift uses newlines as line endings, so that isn't an option:
> 
> 	let xmlData = 
>                     "<?xml version="1.0"?>
> 	             "  <catalog>
> 	             "    <book id="bk101" empty=“”>      // this is not regarded as a comment.
> 	             "       <author>//¯\"_(ツ)_//</author>
> 	             "    </book>
>                     "  </catalog>
> 	             .encoded(as: UTF8)		// This may be a different statement!
That is *not* the case with the \@ data line concept, because the
line ending is part of the data line and is therefore “swallowed”
by the compiler, generating an intermediate variable before it continues
with whatever might be waiting after that. 
> 
> You end up having to artificially add parentheses or other constructs in order to convince Swift that, no, that really is part of the same statement. That's not a good thing.
> 
I think you are wrong here, () are not necessary:  Whitespace and line ends are allowed in-between, for example

     let ar = [4,5,6,3,2]
          .sort()

is perfectly ok.

and so would even be:
let strArray = [ 
    \@………………..
    \@…………
    \@………………..
,
    \\………………..
    \\………………..
    \\…………
    \\………………..
    \\………………..
,
    \@…………………
] .sort()




> (This problem of fitting in well as an expression is why I favor Perl-style heredocs over Python-style `"""` multiline strings. Heredoc placeholders work really well even in complicated expressions, whereas `"""` multiline strings split expressions in half over potentially enormous amounts of code. This might seem at odds with my support for the proposal at hand, but I imagine this proposal being aimed at strings that are a few lines long, where a heredoc would be overkill. If you're going to have two different features which do similar things, you should at least make sure they have different strengths and weaknesses.)

> 
> But you could argue that it's simply a matter of style that, unfortunately, you'll usually have to assign long strings to constants. Fine. There's still a deeper problem with this design.
> 
> You propose a pair of multi-line-only string literals. One of them supports escapes, the other doesn't; both of them avoid the need to escape quotes.
Right.
> 
> Fine. Now what if you need to disable escapes or avoid escaping quotes in a single-line string? What if your string is, say, a regular expression like `"[^"\\]*(\\.[^"\\]*)*+"`—something very short, but full of backslashes and quotes?
No problem:  e.g.

         func foo( parm1: 
             \@`"[^"\\]*(\\.[^"\\]*)*+”`—
            .trim(),                            // Add this If you wish to remove the trailing spaces and line end  (String extension)   
            parm2: 10, 
            parm3: anotherVar)
    

( i like to use lots of vertical space) 

> 
> The constructs you propose are very poorly suited for that—remember, because they're line-oriented,
> they don't work well in the middle of a more complicated expression—
As described they are not intended to be there, but still they can: see function in the following example:

> and they aren't built on features which generalize to act on single-line strings.
?  You can perfectly well process a single data lines (single-line string) like so: 
     func f() 
     {
          var fooRes = foo  (
                                         \@`"[^"\\]*(\\.[^"\\]*)*+”`—
                                         .trim()                                   ).yetAnotherFunction() 
    }



> So now we have to invent some separate mechanism which does the same thing to single-line strings, but works in a different and incompatible way. That means we now have five ad-hoc features, each of which works differently, with no way to transport your knowledge from one of them to another:
> 
> * Single-line strings
> * Disabling escapes for single-line strings
> * Unescaped quotes for single-line strings
> * Multi-line-only strings with unescaped quotes
> * Multi-line-only strings with unescaped quotes and disabled escapes
> 
> My proposal and the other features I sketch, on the other hand, does the same things with only three features, which you can use in any combination:
> 
> * Single- or multi-line strings
> * Disabling escapes for any string
> * Unescaped quotes for any string

Yes, they do, but the solution you propose is stil delimiter-sensitive. 
and therefore prone to data errors. You can’t get around that. 
> 
> This kind of modular design, where a particular task is done in the same way throughout the language, is part of what makes a good language good.

In most cases, yes, but different methods e.g those preferred by FP programmers and e.g. those preferred bij OOP programmers. can and should happily co-exist
in Swift. In this case,  this proposal of yours is not bad all. Imho, neither is mine. 
They both serve different purposes and programming styles. 
they can exist together, as they are on different wave lengths, so to speak.
One is then free to use what fits a certain programming inclination at best. 


@Dave  also
what do you think about this? 
I am trying to avoid the conclusion that most Swift-evolution participants are very much FP biased.
is this the case? 
(some have ventilated this before in different tunes) 
That wouldn’t be too much of a problem where it not for the (hopefully wrong) impressions that:
- Functional Programmers think (like the LISP-ers did in the seventies) that they are superior and Mathematically Correct,
there is no other way, and therefore all else is hopelessly wrong and should be recklessly removed (from Swift in this case)
like removing language elements that are not in line with FP?

Consider for a moment that Swift-Evolution was OOP-dominated
and therefore happily removing closures/lambdas protocols, 
because they have never used it or even do not understand it?
would you accept that?


(protocols in Swift are cool btw, as for me, 
I take the best of both worlds whether FP and/or OOP) 


Have a nice weekend!
TedvG



> 
> -- 
> Brent Royal-Gordon
> Architechies









> 



More information about the swift-evolution mailing list