9 ms·
C# Raw String Literal Proposal
- jmull 5y agoI guess a good thing about proposals like this is as an early warning system. When a language gets its fourth or fifth string literal syntax, its process is probably broken.
- LandR 5y agovar v = """""" contents""""" """""" lol. I like the proposal to have these sort of raw strings, where indentations are removed, but can't they use a symbol before the string like they do with interpolation `$` or literals `@`? I know it says design decision to go with 1 more " than the longest sequence of " in the string, but why ?
- brandmeyer 5y agoI'm a fan of the C++ method. R"SQL(my string without the sequence S Q L goes here)SQL" You can use any extra delimiter you want. The concatenation rules make it easy for you to easily insert source code line breaks and indentation without literal string breaks or indentation.
- Metasyntactic 5y agoHi, I'm the lang designer here. We looked into this. However, there didn't seem to be any benefit to this above just the N-quote version (which fits into how C# does strings everywhere else). In the above case, the `SQL(` and `)SQL` tokens are just akin to N-quotes. Since there's no additional benefit, we went with the simpler approach that solves all these needs, but will look the same across all codebases.
- brandmeyer 5y agoConsistent use of language-specific tags makes it easier for tools to switch to a dedicated foreign-language parser when they encounter a tagged raw literal. The host language just provides the capability through arbitrary matchup, but its still up to users and tool authors to use them consistently. SQL is just one example. Embedded shader programs, XML (fragments), and Protobuf literals are other possibilities.
- GordonS 5y agoI'm in agreement: the function is needed, but the syntax feels really weird. I'd also much prefer some kind of prefix, maybe double "at", e.g. ``` var myString = @@"blah blah blah blah " ``` This feels a lot more natural to me.
- Someone 5y agoA design goal is that you won’t need to escape _any_ character sequence in the string. In your proposal, a " inside a literal string would have to be escaped. In practice, using """ will be sufficient almost all the time.
- fmorel 5y agoIt's more about not needing to escape characters than stripping indentation (that's just an extra perk). Otherwise, if the string can contain `"`, how can the compiler know which `"` defines the end of it?
- taco_emoji 5y agoThey literally explain why as design goal #1: > Provide a mechanism that will allow all string values to be provided by the user without the need for any escape-sequences whatsoever.
- mastax 5y agoRust uses any number of `#` e.g. ###"There can be "stuff without escapes" #" "# "### C# already uses @ for raw string prefixes so they could extend it's usage for multiple prefixes+suffixes. """ Is fine though.
- Metasyntactic 5y ago> but can't they use a symbol before the string like they do with interpolation `$` or literals `@`? Hi! I'm the language designer here :) I know it says design decision to go with 1 more " than the longest sequence of " in the string, but why ? Because if we use a symbol before the string, then there needs to be some mechanism to escape it within the string. e.g. if you use `@` literals, you still need to escape quotes within the string literal. The point of this feature (which we try to spell out in the spec) is so that you can have content without the need to escape anything at all.
- assbuttbuttass 5y agoI always found these complex indentation-stripping rules to be confusing in a language such as Python. I was under the impression that C# doesn't treat whitespace significantly, so why do they need all these complex rules? Just interpret what's between the quotes literally.
- Deukhoofd 5y agoWhen you have multiline strings, and don't want to start the lines with whitespace, it means you need to break the indentation of your code, which can look quite ugly. I'm not sure whether I want the compiler to do it like in the proposal though, I feel like it can easily cause unintentional issues.
- LandR 5y agoWhen I have strings like this, currently I find myself doing something like var foo = "<foo>" + Environment.NewLine + " <bar>" + Environment.NewLine + " <quax>" + Environment.NewLine + "</foo>"; This would fix stuff like this nicely, but it's horrible syntax I think.
- Deukhoofd 5y agoThat would also not be a compile time constant, which would probably be desired in cases like that.
- intrasight 5y agoI did not understand the xml indentation examples
- Metasyntactic 5y agoHi there! I'm the lang designer and i wrote up that spec. Could you clarify what you didn't understand about the indentation examples? I can work on clarifying them. Thanks!
- intrasight 5y agoYou say "If the indentation behavior is not desired, it is also trivial to disable like so:" And the code sample you show differs only in that closing quote isn't indented. You don't explain why and how that change would affect the generated string.
- jodrellblank 5y agoIt says “these string literals will naturally remove the indentation specified on the last line when producing the final literal value.” Each line in the literal will have leading whitespace trimmed off, up to where the closing quotes are. (What happens if the closing quotes pass some of the text?)
- Metasyntactic 5y ago> (What happens if the closing quotes pass some of the text?) That's an error. Called out here: https://github.com/dotnet/csharplang/blob/main/proposals/raw-string-literal.md#example-4---end-delimiter-after-start-delimiter https://github.com/dotnet/csharplang/blob/main/proposals/raw...
- Metasyntactic 5y ago>And the code sample you show differs only in that closing quote isn't indented. You don't explain why and how that change would affect the generated string. Hi there. This is explained in the spec in a few places. In the examples section it explicitly states: > To make the text easy to read and allow for indentation that developers like in code, these string literals will naturally remove the indentation specified on the last line when producing the final literal value. > If the indentation behavior is not desired, it is also trivial to disable like so: I thought that was clear as the prior explanation says that we remove the indentation from teh last line. And then i show how you can disable it. Specifically, as you noted because the closing quote line is no longer indented. Cheers!
- ape4 5y agoPerl's heredoc is better. You get to pick the delimiter. https://perlmaven.com/here-documents https://perlmaven.com/here-documents
- DalekBaldwin 5y agoInterpolation is its own can of worms, but if you just want to be able to encode absolutely anything without escape characters, you just need two delimiters: "*n [stringA] "*n "*n [stringB] '*n '*n [stringC] "*n '*n [stringD] '*n Each string may contain runs of contiguous single or double quotes of length less than n, and furthermore: stringA may start and/or end with a single quote stringB may start with a single quote and/or end with a double quote stringC may start with a double quote and/or end with a single quote stringD may start and/or end with a double quote
- KingOfCoders 5y agoWith all the hacks and exploits going on, and (Log4J) more security awareness coming, I've been considering a safe String class that prevents some characters like CR,LF,\ that are seldom needed in business strings but used in system level things. Drawing a line between these two would increase security.
- bdamm 5y agosafe would be more a property of where it came from, and maybe what processing the string has had on it. Plenty of business strings have newlines. I like the idea but really I want the type to capture unsafe/semi-safe/safe. Now the trick is, how expressive can the idea of semi-safe be?
- KingOfCoders 5y agoJoel tried to fix the problem / source with naming (I remember reading that article, and it's 17 years old!) https://www.joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong/ https://www.joelonsoftware.com/2005/05/11/making-wrong-code-...
- ajnin 5y agoI think it's a good approach but I would do it the opposite way : create an UnsafeString and use that whenever your program takes external inputs. Then make it so that this UnsafeString can't be used directly but must always be consciously converted to (safe) String when using that data anywhere.
- hankchinaski 5y agoI have been temporarily working with c# for the past month after years of Go. It’s a different philosophy to Go, there is a lot of syntactic sugar and magic spells that make your life easy… but I don’t know if I prefer that to the Go way of doing things. I was pleasantly surprised tho. Much better experience than working with Java
- radicalbyte 5y agoI've had to go the other way around.. and I find Go extremely verbose compared to C# - as long as you're not forced to follow certain constraints (SonarCube-driven-development).
- StevePerkins 5y agoIt sounds like you're both saying the same thing.
- radicalbyte 5y agoExactly, we've come from opposite sides and reached the same conclusion :-)
- hackerfromthefu 5y agoIts been fascinating seeing how many people who have not used C# much/in anger, write it off. But also how common the theme is that once people use it a bit they are very pleasantly surprised. This seems particularly endemic in the javascript crowd and its almost as if they have been brainwashed by too many kool aid blogs and don't have broad experience of having tried other technologies, but yet they are so self-assured. I really don't understand why C# isn't used so much more widely in startups, and can only think it's a fashion and misplaced virtue signaling? Genuinely interested in opinions on this, what do you think?
- manigandham 5y ago
- jimworm 5y agoHeredoc by another name...?
- LandR 5y agoDoesn't heredoc preserve the indentation unless you strip it back out ? I don't mean identation within the string, I mean level of indentation of where it is in the code
- jimworm 5y agoThe perl-family heredoc syntax could be quite flexible with options. I'm used to ruby which does have an option for indent-stripping.
- sandreas 5y agoYou can use it without indentication using <<- AND TAB (does not work with spaces, so copy and past won't work on hackernews - replace the spaces of the three content lines with a TAB): cat <<-EOF content not indented EOF
- torginus 5y agoIt seems like .NET is trying to outcompete Rust in the number of string types available in the language.
- ok123456 5y agoRust's different strings are different types with different underlying memory semantics and representations. This is just some syntactic sugar for strings that contain escape codes. It's still just a 'string'.
- tialaramex 5y agoAlso, the Rust language itself only has one string type, str. std::string::String comes ultimately from Rust's alloc crate, it is special only in the limited sense that the prelude makes it available without specifically asking for it, but you could define your own prelude that introduces say MyText or CPlusPlusStyleString or whatever you wanted. Admittedly having one string type is still more than C, or indeed C++ bother with but we might notice that those languages have a pretty terrible relationship with strings and suspect that's not a coincidence.
- sbelskie 5y agoWith potentially more on the way! https://github.com/dotnet/csharplang/blob/main/proposals/utf8-string-literals.md https://github.com/dotnet/csharplang/blob/main/proposals/utf...
- doodpants 5y agoThese aren't different string types, they're different syntaxes for string literals.
- exyi 5y agoI hope it will also normalize newlines to `\n`. The current version of raw literals (@"...") just puts there whatever is in the file, so it in practice depends on if your program was compiled on Windows or Linux. Surely that should be irrelevant for the compilation to intermediate language
- gpderetta 5y agoSurely it depends on the encoding of the source, not where it was compiled?
- rawling 5y agoI think you're right: > Any line breaks within verbatim string literals are part of the resulting string. If the exact characters used to form line breaks are semantically relevant to an application, any tools that translate line breaks in source code to different formats (between "\n" and "\r\n", for example) will change application behavior. https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/lexical-structure https://docs.microsoft.com/en-us/dotnet/csharp/language-refe...
- exyi 5y agoYes it does, but usually \n is committed in git, but on Windows it checks out as \r\n. So you are right that it technically does not depend on the system, but in practice there is a difference.
- gpderetta 5y agoThat's a very good point. Is it best practice to configure git to change line endings on Windows? I understand that these days Windows editors can handle unix line terminators corerctly.
- GoblinSlayer 5y agoAt least in visual studio this seems to be default and there's no way to change it.
- captainmuon 5y agoNice, I'm surprized this is not already in the language. The only thing I find a bit strange is that the delimiters must be on separate lines (unless it is the special one-line-form). So this is apparantly not legal: var s = """This is a multiline string"""; Requiring the start and especially end quotes to be on a separate line makes it take a lot of vertical space. But OTOH, that is consistent with the default coding style in C# which is vertically verbose (with {} on lines by themselves).
- Someone1234 5y ago> I'm surprized this is not already in the language. Because it is already in the language. var xml = @" <element attr=""content""> <body> </body> </element>"; This proposal mostly seems to be about some edge case where @" " syntax isn't good enough. But really, this whole thing is an improvement to an anti-pattern, and you should instead be looking into not needing multi-line block specific string literals in your code (e.g. putting templates in their own files/resources).
- maybeOneDay 5y agoYou've perfectly demonstrated one motivation for this proposal: your string literal is incorrect. Verbatim strings in C# require " to be escaped, your string should be: var xml = @" <element attr=""content""> <body> </body> </element>";
- Someone1234 5y agoAll it perfectly demonstrates is that this is inherently an anti-pattern and that we're discussing features to work around things you shouldn't be doing to begin with. If you want to store XML literals, then by all means do so, but within the code itself is inappropriate. Even the existing @" " syntax is a code-smell, the new syntax doesn't address why that is (e.g. validation/colorization/etc don't work for string literals containing arbitrary other languages). .Net already has constructs to allow the dynamic creation of XML blocks (and JSON) without resorting to string-comcat shenanigans.
- a9h74j 5y agoIn place of all of the special rules for handling indentation, I wonder if they could simply define some extra starting chars (besides $$""" for controlling interpolation) to indicate suppress-leading-newline or suppress-ending-newline etc. Offhand this would seem more explicit than implicit, and be searchable (unlike a pattern). Other than that, ++ for any mechanism to quote to arbitrary depth. I have imagined [abcfoo[ ...anything but ]abcfoo]... ]abcfoo] as another approach.
- crispyambulance 5y agoI got confused at the first example. var xml = """ <element attr="content"> <body> </body> </element> """; And then they say that xml gets this... <element attr="content"> <body> </body> </element> But they don't explicitly say if the new lines after and before the """ 's are considered part of the literal string or not. Are they?
- laurensr 5y agoIn Java the leading [1] newlines are stripped as well as the trailing ones [2]. [1]: https://cr.openjdk.java.net/~jlaskey/Strings/TextBlocksGuide_v11.html#:~:text=all%20of%20the%20indentation%20is%20treated%20as%20incidental https://cr.openjdk.java.net/~jlaskey/Strings/TextBlocksGuide... [2]: https://cr.openjdk.java.net/~jlaskey/Strings/TextBlocksGuide_v11.html#:~:text=red%0A%20%20%20%20green%0A%20%20%20%20blue-,Trailing%20White%20Space,-Trailing%20white%20space https://cr.openjdk.java.net/~jlaskey/Strings/TextBlocksGuide...
- rawling 5y agoNo, although you're right, it doesn't look like they make it clear (although the example is in a little code element which presumably doesn't have leading or trailing newlines). Later on, > In the case of multi_line_raw_string_literal the initial whitespace* new_line and the final new_line whitespace* is not part of the value of the string.
- 5y ago
- gwbas1c 5y ago... Why? There are so many different ways to do strings in C#. Adding features like this just makes the language harder to learn, and the compiler harder to implement. At this point, it's probably better to adjust the compiler to make it easier to turn a text file into a hardcoded string. The embedded resource approach works, but it could be significantly smoother. Or, maybe the compiler needs some form of a plugin architecture so people who want obscure features can figure out how to add them?
- eterm 5y agoIt talks about why, because all those different ways require escaping.
- radicalbyte 5y agoBecause it allows us to literally embed other languages within C# and provide full refactoring, tooling support. Next level stuff this (and something which should be normal, it's 2022 ffs!).
- Metasyntactic 5y agoHi. I'm the lang designer and feature implementor. To your question of "why?", we tried to cover the reasoning in teh proposal. But, the core reason is that today people do use strings a ton. And in many cases it's unpleasant to do so because you always end up with reasons that you need to escape the content. This escaping serves to satisfy the compiler, but really doesn't buy value to teh user the majority of the time. The idea here is that you can just use a raw-string and say: here's the content, exactly as i want it.
- ducharmdev 5y ago> This allows code to look natural, while still producing literals that are desired, and avoiding runtime costs if this required the use of specialized string manipulation routines. Maybe a source generator would be applicable here? Not as nice has having it built into the language of course, but it would at least eliminate these runtime costs.
- StevePerkins 5y agoI like the three-quote literal syntax in general, and am a bit surprised that C# doesn't have this already. Even Java has had this for awhile now! But I don't like the indented form, where nested triple-quotes are ignored. Whitespace formatting is fine when I'm working with Python, but I really don't want to mix that paradigm when I'm working with curly-brace languages.
- taco_emoji 5y agoNested triple-quotes are not ignored, they will end the string if you used triple to start. If you need to include triples quotes within the string, you start with quadruple.
- __ryan__ 5y agoI've given some thought to this kind of string literal in the past (for my imaginary programming language). I want a syntax something like this: var xml = """<element attr="content"> """ <body> """ </body> """</element> """; This would give you the string: <element attr="content"> <body> </body> </element>(no newline) If you wanted a newline at the end, you'd do this: var xml = """<element attr="content"> """ <body> """ </body> """</element> """ """; Basically the end delimiter of the string would be the last """. You could concatenate two strings like so: var xml = """<element attr="content"> """ <body> """ </body> """</element> """ """ // this string ended on this line + """<element attr="content"> """ <body> """ </body> """</element> """ """; // this string ended on this line This could use the same logic for using at least three quotes as the indicator that it's a multiline string. Please, tear this apart and offer improvements. Edit: this is conceptually similar to Zig's multiline literal: https://ziglang.org/documentation/master/#Multiline-String-Literals https://ziglang.org/documentation/master/#Multiline-String-L...
- wangweij 5y agoOne benefit of multiline raw string is that you can directly copy/paste a block of characters between the program and its source. Unless there are very sophisticated IDE support this proposal does not work fine in this sense.
- __ryan__ 5y agoAh, that's interesting. In general, yes my proposal does benefit from and assume some IDE/tooling support for quality of life. Edit: To be specific, the IDE could handle formatting when pasting into a line beginning with """. Or offer a "paste as cool new multiline string syntax" feature.
- deleted 5y ago[deleted]
- radicalbyte 5y agoThe issue is being discussed here: https://github.com/dotnet/csharplang/issues/4304 https://github.com/dotnet/csharplang/issues/4304
- jsd1982 5y agoFor the single-line case, what happens for: """"""" """""""" Are those strings containing `"` and `""` or are they empty strings? Is the first case an error because the starting and ending quote counts do not match? If the number of quote chars is even, do the contents alternate between `"` and empty as the number of surrounding quotes increases?
- rawling 5y agoIt does say > A single_line_raw_string_literal cannot represent a string value that starts or ends with a quote (") though an augmentation to this proposal is provided in the Drawbacks section that shows how that could be supported. so I'd assume the odd count would lead to an error (single trailing "?) rather than a string containing ". E: I'd assume it doesn't allow empty single line strings because otherwise how do you tell the difference between that and the start of a multi line one?
- chhickman 5y agoI would much rather see something like this: string longString = `This ` allows ` differentiation ` of `formatting ` indention ` from ` leading ` string ` spaces ` using ` back-ticks (\`)
- Metasyntactic 5y agoHi there, I'm the lang designer and implementor here. That would violate a core goal of the feature which is that the content itself doesn't need escaping. This sort of approach would require all users to have tooling that would make that pleasant, instead of providing a feature that was easy to use across any editor. Thanks!
- billpg 5y agoA little while ago, I discovered that... $"A{new List<string>{$"B{"{C}"}D"}.First()}E" ... was valid C#. This means that a C# compiler can't start with a simple tokenizing loop. That compiler phase would have to keep track of state in a stack, recording what each } character means while its still looping through code character-by-character. Now we're adding {{ and }} into the equation. Yay.
- torginus 5y ago>This means that a C# compiler can't start with a simple tokenizing loop. Not true, it just means that the parts between double quotes aren't bunched into a single token. To figure out how the compiler makes sense of this code, try https://roslynquoter.azurewebsites.net/ https://roslynquoter.azurewebsites.net/ You'll see how it tokenizes the string.
- billpg 5y agoThat's not a simple tokenizer. A simple loop that would have worked with the 70s era of programming languages, would go through each character and once the boundary between two tokens has been identified, write out a token to a one-dimensional list. This would be a mostly stateless loop, tracking enough state for the current token in hand only. The next phase would go through the tokens and pair up brackets, etc. A C# tokenizer can't do that. It needs to keep a stack of state. When it sees a '}', it needs to know if that's a "normal" brace or the } that resumes a interpolated string literal. I was writing a tokenizer myself and I wanted to have something similar to string interpolation. I very quickly realized my simple loop that I would have written for my CS degree isn't going to cut it and I had to start over.
- Metasyntactic 5y agoHi, I'm one of teh C# language designers, and I work on the compiler implementation as well. C# has never had a "simple tokenizer". Indeed, even the first language has complex lexical constructs that are part and parcel of the language. For example, our comments can store structured data in them (like xml). > A simple loop that would have worked with the 70s era of programming languages Yes. But 70s era compilers had to deal with things like not having enough memory to even store basic amounts of data. It also had to work in spaces where things like a 'stack' was just not tenable. We're literally 50 years from that point, and having a compiler do stuff like keeping a stack is not an issue anymore :)
- monadmoproblems 5y agoI've long wanted a more succinct way of writing implicitly typed arrays. Whenever you work with data directly in the code, for example when hacking on leetcode, you end you with lots of horrible nested arrays: new [] {new [] {1, 2}, new [] {3, 4}}; Something like: @[ @[1, 2], @[3, 4] ]
- Metasyntactic 5y agoHi there! I'm one of the C# language designers. I'm working on a proposal for that right now: https://github.com/dotnet/csharplang/issues/5354 https://github.com/dotnet/csharplang/issues/5354 Thanks!
- monadmoproblems 5y agoYou absolute hero!
- chubot 5y agoTo make the text easy to read and allow for indentation that developers like in code, these string literals will naturally remove the indentation specified on the last line when producing the final literal value. This is the same rule that Oil has; I think it came from the Julia language (or at least that's where I got it from) Oil Has Multi-line Commands and String Literals http://www.oilshell.org/blog/2021/09/multiline.html http://www.oilshell.org/blog/2021/09/multiline.html
- iliketrains 5y agoThis is fantastic! After this is in, can anyone propose a better documentation syntax please? I am really tired of typing verbose XML as comments, and not even being able to write "a < b" or "T<int>" in my comments...
- jwsteigerwalt 5y agoYes!!!!
- wvenable 5y agoI've used this in other languages and I don't like it. It's the wrong approach to solving the problem. As soon as I want to embed some multi-line string in my code then I'd be better of just having it in it's own file. .NET does allow you embed files directly into your project and read in those files but it's a lot of confusing boilerplate. If .NET provided a really easy way to take a file from the project and create a compile-time string from it then I think that would be significantly more useful than this proposal.
- hackerfromthefu 5y agoI like this solution, and agree it would be much better for most cases. C# is beginning to suffer from over-complexity at the language layer, and this solution of making it trivial to reference embedded text files avoid adding more complexity. That said, it's actually pretty easy to reference embedded text files already, not trivial but easy enough.
- bob1029 5y ago> .NET does allow you embed files directly into your project and read in those files but it's a lot of confusing boilerplate. I think "a lot" is a bit of overstatement considering the amount of power you have here. My implementations around embedded resources usually look like this same set of 5 lines: var assembly = Assembly.GetExecutingAssembly(); using var stream = assembly.GetManifestResourceStream("My.Embedded.Resource.png"); using var memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); var myPngBytes = memoryStream.ToArray();