Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

better string interpolation #1250

Closed
antonkulaga opened this issue Aug 12, 2015 · 30 comments
Closed

better string interpolation #1250

antonkulaga opened this issue Aug 12, 2015 · 30 comments
Labels
T-lang Relevant to the language team, which will review and decide on the RFC.

Comments

@antonkulaga
Copy link

things like:

    let name = "Anton".to_string();
    print!("hello {}",name);

are akward and verbose. What about scala-like string interpolation that will work everywhere (not only in print statements)

    let name = "Anton".to_string();
    print!(s"hello {name}"); // Scala uses s"${variableName}" but I think $ is redundant
@steveklabnik
Copy link
Member

We have almost this: https://doc.rust-lang.org/std/fmt/#named-parameters

@nagisa
Copy link
Member

nagisa commented Aug 12, 2015

Making macro take arguments from the context would make them non-hygienic.

@nrc nrc added the T-lang Relevant to the language team, which will review and decide on the RFC. label Aug 25, 2016
@nrc
Copy link
Member

nrc commented Aug 25, 2016

Making macro take arguments from the context would make them non-hygienic.

There are ways to safely allow this kind of hygiene-bending, if we wanted to

@gsauthof
Copy link

To add more examples in addition to Scala: Python 3.6 introduced a similar interpolation style (so called: literal string interpolation with f-strings), e.g.:

var1 = 23
s = f'hello {var1}'
print(s)

And Ruby also has a similar style - e.g.: "hello #{var1}"

@samhh
Copy link

samhh commented Jul 18, 2017

JavaScript too with template strings:

const name = 'Hodor'

console.log(`Hello, ${name}.`)

@damccull
Copy link

I'm brand new to rust, coming from C#. I love C#'s string interpolation:

$"This {stringoutput} is an interpolated string"
"This is not an interpolated string"

The difference is the interpolation is activated by the $ preceeding the quote. Inside the {} can be anything that can go on a single line and output a string.

I'd love to see something like this in rust.

@ChrisCooper
Copy link

Sorry if this is annoying, but it's the same with me coming from Kotlin, which I love:

val age: Int = 10
println("I am $age years old")
println("Next year I will be ${age + 1} years old")

@FUB4R
Copy link

FUB4R commented Jan 19, 2018

I'd like to be able to write this :

println!("Value is {x}", x);

Instead of :

println!("Value is {x}", x=x);

@cdekok
Copy link

cdekok commented Dec 27, 2018

This would be very nice, it would also be nice if this supported none string formats in the cases where you now need to do:
println!("{:?}", scores);
so it would just be
println!("{scores}", scores);

@ArturAmpilogov
Copy link

ArturAmpilogov commented Feb 14, 2019

Having strings name and surname interpolation is handy in many languages:
s"Hello $name $surname" - Scala
$"Hello {name} {surname}" - C#
`Hello ${name} ${surname}` - Typescript and ES6
f"Hello {name} {surname}" - Python
"Hello \(name) \(surname)" - Swift
"Hello $name $surname" - Kotlin, Groovy and Powerhsell

Rust already checks { } during a string format. It may be convenient to use exising behavior and eliminate additonal signs (no $, s, f- or \( signs).
Pure
print!("hello {name} {surname}");

The good thing is that { } can be used for complex expressions, like it's done in Kotlin and C#:
print!("version is {(v + 1)/2}");

An open question is how to describe string declaration, e.g.
let str = "hello {name} {surname}" - this breaks current string declaration behavior,
let str = format("hello {name} {surname}") - this is a bit lengthy.

@vvaidy
Copy link

vvaidy commented Feb 14, 2019

@ArturAmpilogov ... and let's not forget:

# echo "Hello $NAME $SURNAME" # bash and sh

I must confess it astonished me when I started in rust that a modern language did not not support string interpolation. Still surprises me :-)

@enormandeau
Copy link

enormandeau commented Feb 26, 2019

I know this issue is old, but string interpolation would make our lives better (more fun and easier).

# I prefer
outfile.write(
    format!("{x}\t{y}\t{z}\n")
        .as_bytes()
)

# over
outfile.write(
    format!("{}\t{}\t{}\n", x, y, z)
        .as_bytes()
)

# and
outfile.write(
    format!("{x}\t{y}\t{z}\n", x=x, y=y, z=z)
        .as_bytes()
)

The first one is much easier to inspect than the second and third versions.

@hsandt
Copy link

hsandt commented Apr 6, 2019

Could we write a macro that simulates the third version by typing @tcalvert's version?

injected_format!("{x}\t{y}\t{z}\n", x, y, z)
// expands to
format!("{x}\t{y}\t{z}\n", x=x, y=y, z=z)

Even if not in the standard, I'd like to know if a user can make his/her own injected_format!.

Although I don't like the redundancy in this syntax (why is there x again? is it the same x?), at least the order of the arguments doesn't have to match the order of usage, e.g.:

injected_format!("{x}\t{y}\t{z}\t{x}\n", z, y, x)
// expands to
format!("{x}\t{y}\t{z}\t{x}\n", z=z, y=y, x=x)

also works. Which means if you want to reorder the interpolated variables, you don't have to reorder them at two places.

Ideally we would have a macro that parses everything inside the braces and generates the named arguments for them, only once:

simple_format!("{x}\t{y}\t{z}\t{x}\n")
// expands to
format!("{x}\t{y}\t{z}\t{x}\n", x=x, y=y, z=z)

This can work, because evaluating simple variables should have no secondary effect (unless you write some tricky Display/Debug fmt method that modifies some static!), so the order in which we choose to put named arguments doesn't matter (we could just add them in the order we encounter the variables in the format pattern).

However, the macro would probably be much more complex, being able to handle cases like brace escaping ({{pure text}}).

@ct-austin
Copy link

It turns out we can write a proc macro to do this now: https://crates.io/crates/ifmt.
Only works on nightly with #![feature(proc_macro_hygiene)], but once proc macros are allowed in expression position it should work on stable (there are still some error-reporting kinks to be worked out, although hopefully writing such a string isn't too error-prone).

Handles expressions (iformat!("3+2={3 + 2}")), brace escaping ({{/}}), format specs ({x:?}), and even dirty nested raw strings:
iprintln!(r##"{format!(r#"because why not? {}{}"#, ':', "}")}"##);

@damccull
Copy link

Wow. That's pretty cool. I'm still new enough that I'm not sure how macros work, but I assume you just wrapped the basic ones in a new version that parses the string for formatting tags and replaces them?

@tesuji
Copy link
Contributor

tesuji commented Apr 21, 2019

This may break backward compatibility.

@chichid
Copy link

chichid commented May 3, 2019

+1 for this feature, I'm new to Rust, and I think anything related to string manipulation is of paramount importance. Especially when it comes to making REST APIs or front-end and GUIs

@ExoticMatter
Copy link

ExoticMatter commented May 8, 2019

This may break backward compatibility.

But would it really? All of the formatting macros require parameters to be passed when the format string contains any {_}s.

let x = 42;
println!("x: {x}"); // error: there is no argument named `x`

Since it seems this would only affect code that is currently illegal, it should be trivial to have formatting macros that can handle both the current style and interpolated strings:

#[doc(hidden)]
pub use {std::println as _std_println, ifmt::iprintln as _ifmt_println};
#[macro_export]
macro_rules! println2 {
    ($fmt:expr) => ($crate::_ifmt_println!($fmt));
    ($fmt:expr, $($args:tt)*) => ($crate::_std_println!($fmt, $($args)*));
}
println2!("a number: {42}");
println2!("another number: {}", 360);
a number: 42
another number: 360

@serak
Copy link

serak commented Jul 19, 2019

I think JavaScript should interpolate string as Rust not the other way round , in rust inside {} parenthesis we can do a lot of trick on the interpolation , the only problem with rust interpolation is you have to track the position of the string. or if everybody still needs JS like interpolation then Rust should go with something like the angularjs interpolation {variable | formating} e.g {{ date | date : format : timezone }}
(forget about double mustache and use single one of course)

@obvionaoe
Copy link

+1 Kotlin styled string interpolation

@tesuji
Copy link
Contributor

tesuji commented Jun 21, 2020

Dup of #2795?

@AndrewSav
Copy link

@lzutao It appears that the PR you linked could be a proposed implementation for this issue. I'm not sure on the "Dup" thing though, since usually PRs that solve an issue are not considered "Dups". Most often people refer to one issue as a Dup of another if they are essentially both the same issue.

@ct-austin
Copy link

@lzutao

That RFC is only for implicit capture of identifiers, supporting format!("{foo}") but no expressions beyond that.

I think this RFC should be used to discuss potential expansions to expression or dotted access interpolation, maybe using the suggested format!("{(a.b)}") syntax.

@benorgera
Copy link

benorgera commented Oct 15, 2021

Haven't tried yet but with some nightly features i think this exists here: https://github.com/anowell/interpolate

@insinfo
Copy link

insinfo commented Oct 20, 2021

@benorgera
good job on string interpolation.
I come from other languages ​​like C#/Java/Dart... among other languages, and I also think that string interpolation is kind of standard in modern languages ​​today, I feel rust is missing a bit on that, I see rust is very verbose for simple things, i think the compiler has to be smarter to make the programmer's life easier and not harder.

@tyoc213
Copy link

tyoc213 commented Mar 12, 2022

This is now stable afaik, should be closed?

@AndrewSav
Copy link

@tyoc213 can you provide some details please? (E,g. a link documenting the current state of the feature would be perfect)

@polarathene
Copy link

polarathene commented Mar 13, 2022

@AndrewSav probably referring to changes with Rust 1.58 (Jan 2022)? This page details what you can do fairly well.

This doesn't allow for expressions within the string (which the discussion here seems to have changed towards, but could be raised as a separate issue), you'd still need to do that externally, but is mostly the same beyond that.

@frewsxcv
Copy link
Member

frewsxcv commented Mar 6, 2023

@rust-lang/lang What do you think about closing this?

@scottmcm
Copy link
Member

scottmcm commented Mar 6, 2023

I agree with close -- https://blog.rust-lang.org/2022/01/13/Rust-1.58.0.html#captured-identifiers-in-format-strings covers what was in the OP here.

People can always make new IRLO or Zulip threads to discuss potential extensions, though I'm fairly sure it'll never be "any expression", and thus any proposal would need to justify a small-but-useful-enough addition.

@scottmcm scottmcm closed this as completed Mar 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-lang Relevant to the language team, which will review and decide on the RFC.
Projects
None yet
Development

No branches or pull requests