Stream: beginners

Topic: Raw string literals


view this post on Zulip Ayaz Hafiz (Aug 14 2022 at 18:09):

Does Roc have support for raw string literals? E.g. r#"..."# in rust.

view this post on Zulip Richard Feldman (Aug 14 2022 at 18:22):

we have triple quoted strings, which I kinda assume should suffice in practice

view this post on Zulip Richard Feldman (Aug 14 2022 at 18:23):

that is, they suffice for the use case of wanting unescaped quotation marks in them :big_smile:

view this post on Zulip Richard Feldman (Aug 14 2022 at 18:23):

they still support string interpolation

view this post on Zulip Richard Feldman (Aug 14 2022 at 18:23):

which I assume shouldn't be a problem in practice?

view this post on Zulip Richard Feldman (Aug 14 2022 at 18:23):

but I guess it depends on what you're looking to do with them!

view this post on Zulip Ayaz Hafiz (Aug 14 2022 at 19:29):

Cool, that works

view this post on Zulip Folkert de Vries (Aug 14 2022 at 19:33):

do we handle indentation in those? python and elm don't and it's really annoying if you want one of those in a nested scope

view this post on Zulip Folkert de Vries (Aug 14 2022 at 19:34):

basically, I would like indoc! to be the default behavior

view this post on Zulip Ayaz Hafiz (Aug 14 2022 at 19:38):

yeah:

» foo =
…   """
…   asdasda
…   adsd
…   """
… foo

"asdasda
adsd" : Str

view this post on Zulip Folkert de Vries (Aug 14 2022 at 19:40):

ah, nice

view this post on Zulip Richard Feldman (Aug 14 2022 at 20:26):

yeah the rule is that in a multiline triple-quoted string, you have to indent the opening and closing """ delimiters at the same level of indentation, and then that indentation level is treated as the beginning of the line for all the lines in between the delimiters

view this post on Zulip Richard Feldman (Aug 14 2022 at 20:26):

that said, I just realized the above repl output is syntactically invalid, and it should actually have printed the result using triple-quoted strings! :big_smile:

view this post on Zulip Richard Feldman (Aug 14 2022 at 20:27):

like it should have printed:

"""
asdasda
adsd
""" : Str

view this post on Zulip Richard Feldman (Aug 14 2022 at 20:27):

I'll open an issue for it

view this post on Zulip Richard Feldman (Aug 14 2022 at 20:29):

https://github.com/roc-lang/roc/issues/3793

view this post on Zulip Ralf Engbers (Aug 15 2022 at 11:19):

Richard Feldman said:

https://github.com/roc-lang/roc/issues/3793

The issue says "foo\nbar" (single-quoted) should be printed as:

"""
foo
bar
""" : Str

But "foo\nbar" is just as syntactally incorrect as

"foo
bar" : Str

and the REPL should give you an "I cannot find the end of this block string" error, should it not?

view this post on Zulip Ralf Engbers (Aug 15 2022 at 11:27):

Ayaz Hafiz said:

yeah:

» foo =
…   """
…   asdasda
…   adsd
…   """
… foo

"asdasda
adsd" : Str

I assumed it would be just a formatting issue, but it seems to be a parsing issue. When you enter """foo\nbar""" in the REPL, that is being parsed as a PlainLine instead of a Block. I checked out compiler/parse/src/string_literal.rs, but could not see why this would happen.

This is right place in the code, where the parsing for any string literal happens, right?

view this post on Zulip Anton (Aug 15 2022 at 11:43):

@Joshua Warner

view this post on Zulip Ralf Engbers (Aug 15 2022 at 11:48):

Ralf Engbers said:

and the REPL should give you an "I cannot find the end of this block string" error, should it not?

I think I misunderstood triple-quote strings (I always saw them as unescaped raw strings like in Kotlin). But still, if "foo\nbar" is syntactically correct, should the REPL print "foo\nbar" : Str or the multi-line triple-quoted string?

view this post on Zulip Richard Feldman (Aug 15 2022 at 12:39):

ah, I should have clarified! :sweat_smile:

view this post on Zulip Richard Feldman (Aug 15 2022 at 12:39):

yeah, the whole issue is that the repl should print the multi-line triple quoted string

view this post on Zulip Richard Feldman (Aug 15 2022 at 12:42):

both of these are syntactically valid:

"foo\nbar"
"""
foo
bar
"""

however, this is not syntactically valid:

"foo
bar"

so the issue is that the repl should print the triple-quoted version

view this post on Zulip Ralf Engbers (Aug 16 2022 at 11:41):

I have this working by adjusting fmt_string_literal in compiler/fmt/src/expr.rs and changing

PlainLine(string) => buf.push_str_allow_spaces(string);

to

PlainLine(string) => {
            let mut lines = string.split("\n");
            // This match will either be (Some(first), None) for single line strings,
            // or (Some(first), Some(second)) for multiline strings.
            match (lines.next(), lines.next()) {
                (Some(first), Some(second)) => {
                    buf.push_str("\"\"");
                    buf.newline();

                    for line in [first, second].into_iter().chain(lines) {
                        buf.push_str_allow_spaces(line);
                        buf.newline();
                    }

                    buf.push_str("\"\"");
                }
                _ => buf.push_str_allow_spaces(string),
            }
        }

However, this function is used in many places (well, format_with_optionsis, which calls this one) and I am not sure this would make sense as a general change, or whether there is an easy way to make this change only for the REPL. Pointers and comments are very welcome! =)

Btw, to be consistent in the output, the REPL would turn "\n" into two empty lines:

"""


""" : Str

view this post on Zulip Ralf Engbers (Aug 16 2022 at 11:45):

One specific reason why I am not confident in this change: for this to work, we would need to remove debug_assert!(!self.beginning_of_line) and debug_assert!(!s.ends_with(' ')) from push_str and push_str_allow_spaces, because those things can now happen in the REPL.

view this post on Zulip Ralf Engbers (Aug 23 2022 at 09:29):

Taking another look, I think it works like this (and of course without removing the debug_asserts). This is the PR. Always happy for feedback!

view this post on Zulip Tommy Graves (Dec 02 2022 at 16:35):

Having no option other than indoc! as the multiline string behavior has been a bit annoying to me during advent of code so far. I'm writing tests for each day by copying the examples given in the prompt, like so: https://github.com/TAGraves/adventofcode2022/blob/main/day1.roc#L39-L57

The indoc! behavior means I have to paste in the example input and then indent it, instead of being able to paste it in directly. And when I want to copy it to my day.txt file (so I can run and debug the application using roc run instead of roc test, I have to un-indent it after pasting it into the text file :sad:.

view this post on Zulip Richard Feldman (Dec 02 2022 at 16:38):

a feature I've had in the back of my mind for a few years is a way to say "import this file as a Str" or "import this file as raw bytes"

view this post on Zulip Richard Feldman (Dec 02 2022 at 16:38):

would that address this use case?

view this post on Zulip Richard Feldman (Dec 02 2022 at 16:39):

the thing I don't like about allowing for arbitrarily-outdented strings is that it makes the source code harder to read later on, because some things are outdented totally differfently from everything else :sweat_smile:

view this post on Zulip Tommy Graves (Dec 02 2022 at 16:48):

the thing I don't like about allowing for arbitrarily-outdented strings is that it makes the source code harder to read later on, because some things are outdented totally differfently from everything else

Interesting! I've not personally found that to be the case, but looking at some examples I understand what you're saying.

I think importing files as strings and having roc format fix incorrectly-indented multiline strings could both help (though this one might be tricky to infer the correct way to format it!), if we don't want to provide the option to opt out of indoc!.

view this post on Zulip Anton (Dec 02 2022 at 17:48):

a feature I've had in the back of my mind for a few years is a way to say "import this file as a Str" or "import this file as raw bytes"

I like that idea a lot!


Last updated: Jul 06 2025 at 12:14 UTC