Longer quoted strings
I propose we add longer quoted strings (7+ quotes since 6 quotes specify an empty triple-quoted string) for when we need to embed source code that contains triple quoted strings. It is in line with C#'s design of raw string literals with variable length of starting quotes. Here, we can follow C#'s design of the multiline literal with the end delimiter specifying the indentation size (must be whitespaces, not any other character):
let fsharpCode = """""""
let string = $"""{String.replicate 3 "Hello World!\n"}"""
"""""""
let fsharpCode' = """""""
let string = $"""{String.replicate 3 "Hello World!\n"}"""
"""""""
fsharpCode = fsharpCode' // true
The newlines directly next to the delimiters will not be included in the string. Therefore, the string has the following content without preceding or succeeding newlines:
let string = $"""{String.replicate 3 "Hello World!\n"}"""
Since 7 quotes are already quite long, we won't allow single-line versions of it. So these are illegal:
let fsharpCode = """""""let string = $"""{String.replicate 3 "Hello World!\n"}""" """"""" // error - no single line version
let fsharpCode' = """""""
let string = $"""{String.replicate 3 "Hello World!\n"}""" """"""" // error - ending delimiter must be on its own line
let fsharpCode'' = """""""let
string = $"""{String.replicate 3 "Hello World!\n"}"""
""""""" // error - starting delimiter must be followed by a newline
The minimum lines that a longer quoted string must occupy is 3:
let empty = """""""
""""""" // error - too short - leave some space for adding content!
let empty' = """""""
""""""" // ok
This is because the starting delimiter requires a newline after, and the ending delimiter requires a newline before.
Interpolation will work:
let fsharpCode = $$"""""""
let string = $"""{String.replicate %%d{{3}} "Hello World!\n"}"""
"""""""
and produces the same string as before. The existing way of approaching this problem in F# is to use runtime string manipulation which is less visually appealing and costs performance.
Pros and Cons
The advantages of making this adjustment to F# are
- Alignment with C#
- Convenience
- Visual appeal compared to triple quoted strings
The disadvantage of making this adjustment to F# is the learning complexity and implementation and maintenance costs.
Extra information
Estimated cost (XS, S, M, L, XL, XXL): S to M
Related suggestions:
- https://github.com/dotnet/csharplang/issues/4304
Affidavit (please submit!)
Please tick these items by placing a cross in the box:
- [x] This is not a question (e.g. like one you might ask on StackOverflow) and I have searched StackOverflow for discussions of this issue
- [x] This is a language change and not purely a tooling change (e.g. compiler bug, editor support, warning/error messages, new warning, non-breaking optimisation) belonging to the compiler and tooling repository
- [x] This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it
- [x] I have searched both open and closed suggestions on this site and believe this is not a duplicate
Please tick all that apply:
- [x] This is not a breaking change to the F# language design
- [x] I or my company would be willing to help implement and/or test this
For Readers
If you would like to see this issue implemented, please click the :+1: emoji on this issue. These counts are used to generally order the suggestions by engagement.
We may also add language markers as specified in this C# proposal.
let mystr = """""""html
<html>
<body>
<h1>Heading</h1>
<p>Paragraph</p>
</body>
</html>
"""""""
This is a nice suggestion. We get the desirable feature of correct indentation for long strings while keeping the language backward compatible – and at 7 (or more) quotes the behavior is identical to C#.
F#:
let myStr =
"""""""
<html>
<body>
<h1>Heading</h1>
<p>Paragraph</p>
</body>
</html>
"""""""
C#:
var myStr =
"""""""
<html>
<body>
<h1>Heading</h1>
<p>Paragraph</p>
</body>
</html>
""""""";
However I would suggest that this proposal is focused on nicely quoted strings, and that syntax highlighting is kept to a separate proposal that would work on all types of strings, e.g. standardize Rider's "language injection" feature:
let myStr1 =
// lang=html
"<b>hello</b>"
let myStr2 =
// lang=html
"""<b>hello</b>"""
let myStr3 =
// lang=html
"""""""
<b>hello</b>
"""""""
I actually think this suggestion should be implemented solely due the readability benefit this would bring to the Fantomas test cases. Imagine how much nicer a file like this would read with correctly indented multiline strings.
It's been a pain point for FSAC test cases as well. We've made a whole helper library for dealing with the current indentation-appended strings.
If approved I might be able to implemented as some point.
I understand the need, and I assume the test cases for source code related tools are the biggest motivator here. The workaround is either runtime helpers for trimming left-side whitespace, or storing the source code in a separate text file (which has also the added advantage of not causing a recompilation if the code is changed, btw.).
I do not want to immediately approve this, even though this is perfectly doable and if starting at 7 " symbols, does not risk backwards compat issues. Reason is, there are already too many forms of strings and I do not like the idea of having YET another one.
Especially of this yet another one would not only allow more quotes inside (this feels OK), but would also have a different treatment to left-side whitespace compared to all other strings.
Also, isn't the source-code as string motivation a never ending one? Triple quote strings were added to easily create strings that have a quote in them. If 7-quote strings are added to the language, how would tests for code with them be created? ( I realize this asks for a general feature with 7+ quotes going up to many. But maybe it is a signal to store the content separately?)
Also, isn't the source-code as string motivation a never ending one? Triple quote strings were added to easily create strings that have a quote in them. If 7-quote strings are added to the language, how would tests for code with them be created? ( I realize this asks for a general feature with 7+ quotes going up to many. But maybe it is a signal to store the content separately?)
I think the variable length approach solves this in an elegant way (https://github.com/dotnet/csharplang/blob/345fa10e4f19b5510b60cbc4822ad953213a906f/proposals/csharp-11.0/raw-string-literal.md).
E.g. if you have a source code snippet with 8 quotes in it then you wrap it in 9 (or more) quotes.
The source code use case if often lots of small snippets (few lines). So having them directly in the test code is highly preferable compared to maintaining many separate tiny files and linking them correctly (it would also complicate PR reviews greatly – including AI assisted ones).