"""
For string interpolation, \ feels worse, since that's where characters are most often escaped in other languages. It re-uses the symbol assigned for lambdas, which was also confusing for a bit. I personally would've liked to see Hello $(world) or Hello ${world}, I think there's value in being consistent here.
"""
I'm also not a fan of \ for the simple reason that it breaks my vim editor tooling. The ( in \( is escaped and that breaks various shortcuts
I quite like the rust/python {} approach. it's fairly simple and also easier to type than the \
adding in a $ does not really seem needed to me, but I don't mind it either
but then you have to escape { and } instead
this has already concretely been a pain in glue generation in Rust, where whenever I copy/pasted a Rust or C code snippet into a Rust format! literal (because I wanted interpolation for things that were being generated), I had to replace all the {s with {{
the nice thing about \ is that it's already reserved (for character escapes) so it never requires extra escaping
I'd say our use case was very non-standard
maybe another way of saying it is: \ has an objective benefit with nonzero real-world upsides: it doesn't require anything else to be escaped.
I think every other syntax alternative which doesn't have that objective benefit needs to clear the bar of "so much subjectively better that it outweighs that objective benefit"
personally {...} doesn't clear that bar for me (aesthetically I don't have a significant preference either way, honestly)
I'm open to others feeling differently, but that's where I think the bar is! :big_smile:
for ${} only the specific combination ${ would need to be escaped as \${
true, although at that point ${...} is the same number of characters as \(...) except with needing a rare extra escape, so is that really so beneficial?
(I guess maybe for Vim shortcuts it is)
for me, yes
yeah
as an aside, I prefer parens in the hypothetical future where we allow more expressions in there
so would $(...) work just as well?
it also will look more familiar, though I don't think this is hard syntax to learn
it gets trickier when you allow custom number formatting, but that is inherent
I'm skeptical of number formatting in string literal syntax being a good idea
I'm open to being convinced otherwise, but that's my general sense
like https://package.elm-lang.org/packages/coinop-logan/elm-format-number/latest/ seems like a better general strategy to me
yes, probably
those things are a bit like regexes
you copy-paste, they cannot be understood, only written
45 messages were moved from this topic to #ideas > display and log by Richard Feldman.
i actually love the current way
it just aligns with how you actually do "non standard character stuff" (not claiming that newline isn't standard but you catch my drift)
i empathize the tooling aspect but perhaps there's an editor specific solution for it
Richard Feldman said:
so would
$(...)work just as well?
the idea of switching to specifically this syntax has been growing on me over time. I now think it's worth considering as an actual change.
reasons:
$(...), and most languages use $ as the starting character even if they don't use parens; only Swift and Roc currently use \ instead)\ for this breaks some editor tooling (Vim, in this case)\ already means "escape," the number of times someone actually wanted to write $( in a string literal and was inconvenienced by having to backslash-escape it is probably about zero, so the upside of \ already meaning "escape" seems close to zero in practice.\ looks awkward in string literals that have slashes, which makes Roc interpolations involving file paths and URLs harder to read than in other languages. Compare:"/users/\(username)/posts/\(postId)"
"/users/$(username)/posts/$(postId)"
it's even worse in Windows file paths (which are already bad enough to begin with due to having to backslash-escape all the backslashes):
"C:\\\\\(directory)\\\(filename)"
"C:\\\\$(directory)\\$(filename)"
also, with $(...) we could consider supporting $email (without parens) in the common case where you just want a particular variable and don't need parens to disambiguate, e.g. $(user.email) or $(Num.toStr num). Compare:
"/users/$(username)/posts/$(postId)"
"/users/$username/posts/$postId"
Actual currency always starts with a number (and variables can't start with numbers), so $1 would never interpolate. Also, since Roc is a type-checked language, if you wrote $user.email and forgot the parens, you'd find out at compile time (if user.email would have worked, then user is a record, so $user is a type mismatch because interpolated values must be strings), and of course if user wasn't defined at all, you'd find out about that at compile time too.
anyone have thoughts on this?
Then you just have to escape when using $. Also, would unicode become $u(123)
I think Unicode escape syntax can be considered separately from string interpolation; after all, it is in most languages
Brendan Hansknecht said:
Then you just have to escape when using
$.
what would be an example of when this would come up though?
like you'd have to specifically want to write $( (or in the case of the $user idea, $ followed by a non-number) to have to escape $
I would assumed you just always escape it for consistency. Otherwise it would be a compile warning.
oh I wouldn't think so - I don't see people doing that in the languages which use $ for interpolation, so I assume they wouldn't in Roc either :big_smile:
to put it another way, I would assume that if we made this change, everyone would change all the \( to $( and that would be the only change anyone would (or would have to) make
unless we also did the $name thing, in which case people might optionally choose to shorten some of the interpolations (or maybe roc format would make that change automatically)
ok
In that case, only other thought is that we may use $ for shadowing. So how would you interpolate a shadowed value and would that look really bad. Long form $($buf), short form $$buf?
the current proposal is that if you have $user in scope, you can't also have user in scope
which means that $user in interpolation could unambiguously refer to either $user or user, whichever was in scope
but also I think it's fine if $($user) was required, since the goal of the shadowing experiment is to make it be opt-in and slightly higher-friction than not using shadowing anyway
Sounds good. Yeah. I approve of the change
@Joshua Warner can you think of any parsing implications for this change? (positive or negative)
If your string is like "hello,$user.name!" is the .name part a part of the variable being interpreted or the string?
Like how do you know where the variable ends and string starts again?
Oh, wait this isnt permitted and would be a type error. Got it.
I like this idea a lot!
I like the idea of using $(), but am less keen on only having interpolation without parens. Even if the rules for just $ are unambiguous, it seems like a source of confusion. For example, it might be surprising to see that “$foo” interpolated, but then “$1” did not. To me, adding parentheses is so negligible that it doesn’t seem worth making things more confusing to avoid typing them occasionally.
Then you would also end up in more situations where you have to go back and add parentheses where you thought you wouldn’t need them. For example, if you need to change “$foo” to $(Num.toStr foo)”. I would rather not have the option to use $ vs $() and instead always be consistent necessarily.
I doubt this would come up much, but you would also have weirdness for any strings like this “ca$h”
Richard Feldman said:
only Swift and Roc currently use
\instead)
And CUE. There are probably others as well.
I do rather like \(...). I don't think there really needs to be a distinction between the character used for traditional "literal" escapes, and the character used to for interpolation. Having them be the same means that I can paste more strings successfully without needing to worry about all the potential interpretations that might have.
\ has a lot of unused range in terms of the character that follows it. \(...) is just making good use of that range.
In terms of editor misinterpretation, that can get solved with tooling improvements (like with treesitter support for Roc).
I use vim as well, but it gets confused even in mainstream languages whenever I have '{' (i.e. a string or char containing a brace), so I won't claim its brace/parens tracking is at all sophisticated. Thus I don't think that minor editor blunders are a compelling reason to change the language.
what do you think about the other reasons?
Another thought about using $ alone: it means that there would need to be a rule to determine which interpolation to use here
x = "hello"
xy = "world"
"$xyz"
The especially undesirable part of this is that if I removed either x or xy, the value being interpolated would silently change. I would much prefer it to be explicit and cause an error.
I don't think using $() instead of \() meaningfully changes the parser/lexer. If we didn't allow parens (i.e. only $xyz), that would make doing lexing separately somewhat easier.
I like the symmetry of the current \() with other escape sequences, but that's a pretty minor preference.
it's even worse in Windows file paths (which are already bad enough to begin with due to having to backslash-escape all the backslashes)
Lol windows paths are the worst
Richard Feldman said:
what do you think about the other reasons?
I think the familiarity point has some merit, but I don't think it's a steep learning curve difference either way. The approachability (or not) of Roc isn't going to boil down to just choice of interpolation syntax, and of course is dependent on programmer background.
I suspect ${...} will feel more familiar to most readers for simple expression interpolation. It's true that bourne shells have both ${...} and $(...), though the former is probably the closer analogue to what most uses of Roc interpolation will look like.
I agree that $ is more visually distinctive/readable in dense strings compared to \. In strings with more spacing, there is not much readability difference.
I believe we should be cautious about $user style interpolation. Speaking of shells, some bash style guides explicitly discourage this shorthand style in favor of explicitly-braced interpolation.
We can always introduce the shorthand syntax later if we determine it's worth the tradeoffs, after gaining experience with the longer, delimited syntax.
yeah the difference in strings with slashes in them is the biggest usability delta to me, and it comes up often when working with paths or URLs
PR to introduce $(...)
An admittedly minor benefit is that $() is a tiny bit easier to type as you can just stay at the numbers row with the shift key pressed
Think about the kilometers of finger travel saved :big_smile:
in the parens-and-commas world, it might make sense to adopt the much more popular ${...} interpolation syntax, to avoid repeated parens.
with whitespace calling, $(Num.toStr foo) is nice, but with parens-and-commas, I think $(foo.to_str()) is less nice than `${foo.to_str()}, especially if the curly braces can be syntax-highlighted differently from the parens
anyone have thoughts on that?
Sounds reasonable...though not particularly major either way. Also, would we consider just {} like in a number of other languages.
So just {foo.to_str()}
{} and ${} both seem better with PNC. I like {} more, haven't found an instance where the extra $ was helpful.
my main thoughts on $ vs. just braces are:
$ isn't used anywhere else in the language, and it would be nice to not have it at allI guess I am used to rust, python, and zig just using {}. I guess I don't print { too often so mostly don't notice.
No real opinion on dollar otherwise
I was always slightly preferential to the backslash. Nice symmetry with other escapes in strings.
Just using plain curlies is annoying anytime you’re outputting code, json, etc.
if we didn't have $, what would be the syntax for escaping curlies? backslash curly?
Yeah backslash seems the obvious choice under those constraints. But $ doesn’t seem terrible to me either
I guess an argument for braces alone is that it makes the common case nicer and more concise at the cost of having the edge case be annoying
and I guess for normal application development in Roc, outputting code should be rare and things like JSON should be done with a library anyway
Another option, I honestly don't know which is better, is to have 2 different string types like python. There, only 'f-strings' interpolate. So the literal f"Hello, {name}" would interpolate the variable name. However the literal "Hello, {name}" would not.
I think JS has a similar thing with backticks vs quotes for string literals
I have a strong preference for only having one string syntax :big_smile:
Fair. I would say I have a slight preference for $ or \ in front of the braces in that case, to avoid having to escape otherwise
\ had the problem of making paths look confusing, e.g. /foo/bar/\{baz}/blah so I don't think we should go back to that :big_smile:
to me, it's between ${ ... } and { ... }
based on how annoyed I've been with braces-only in the Roc code base, I'd prefer ${ ... } but I'm not sure how much of that is just due to the coincidence of writing a compiler in Rust
it isn't annoying at all at Zed, for example
I do kinda like the idea of always using ${ ... } and just never even thinking about escaping
because needing to escape never comes up
I guess Ruby syntax would also be fine, e.g. #{ ... }
which would have the upside that # is already a character used in Roc syntax, which could have some lexing performance benefits, although:
#{ ... } is much less commonly found in other languages than ${ ... }# already means comment in Roc syntax which might feel a bit strange (although it also means comment in Ruby, and that seems to be fine in practice)overall ${ ... } seems like the nicest option to me, because it means you basically never have to even think about escaping, and it's more familiar to more beginners than #{ ... }
does anyone feel strongly that we should do something different?
I am down for the consistency of ${...} for the reasons you describe
My preference is also for ${...}
ok cool, let's go with ${ ... }!
I'm working on a blog post to announce purity inference, and I'll use it in that (since that blog post will also use parens-and-commas as well as snake_case)
I'm assuming it'll be a quick enough change that we can get it in before the blog post is done anyway :big_smile:
(also I want to hold off on publishing it until we've removed Task from builtins, and other related cleanups)
Fully remove task or deprecate it and update the core platforms to PI.
I think we should fully remove it. It's going to be very confusing for people if we keep it in the builtins and Tutorial.
I assumed we'd keep it around for a bit as other platforms migrate, but I'm always happy with ripping things out sooner
I'm good with a full removal as well
Last updated: Jun 16 2026 at 16:19 UTC