interpolate icon indicating copy to clipboard operation
interpolate copied to clipboard

Suggestion: Swift-like string interpolation

Open Boscop opened this issue 7 years ago • 3 comments

I think this crate has potential and I want to use it a lot..

Btw, I also think there should be a shorter way to concatenate strings in Rust than "foo".to_string() + "bar", so with this crate it would be s!("foo") + "bar", right?


In swift, it allows exprs in the interpolated string like this: https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html#ID292

let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
// message is "3 times 2.5 is 7.5"

This would allow not just simple variable interpolations but actual expressions!

let s = s!("foo $(bar * 2) baz");

Boscop avatar Jul 26 '18 13:07 Boscop

This would allow not just simple variable interpolations but actual expressions

Expressions are supported, just not documented on the README. You just barely guessed the wrong syntax: it's currently ${bar * 2}. See this test


I think this crate has potential and I want to use it a lot..

Thanks. It means a lot. I've actually been considering an update to this with an alternative syntax. Instead of using $foo or ${foo}, I'd like to change it to {foo}. It's more intuitive (when guessing how to use it with expressions) and more similar to the format strings actually supported in the std lib.

I'd really love to see is some way to make this macro work with literal-prefix syntax, but that would require an RFC that feels like a long-shot.

... simple expression raw string literals
current s!("$foo") s!("${foo + 2}") s!(r#"She said, "$foo""#) (broken)
alternative s!("{foo}") s!("{foo + 2}") s!(r#"She said, "{foo}""#)
s-literal s"{foo}" s"{foo + 2}" s#"She said, "{foo}""#

Curious what you think of the alternative?

anowell avatar Jul 27 '18 08:07 anowell

The $ syntax requires only one additional keystroke when the interpolated expression is only a variable (probably most cases) but 3 additional keystrokes for general expressions, whereas {} syntax always requires two. The optimal / most concise solution would require one additional keystroke for single-var exprs and 2 for general exprs.. E.g. if single-var exprs would use $ in front, but general exprs would use {} around them.. That would not be consistent though, but still easy to remember, because the single-var case would be the most common (so it would be remembered easily) and the {} syntax is already familiar from fmt ;) Even though I'm often a fan of consistency, in my experience it's very convenient to be able to interpolate single vars with just one extra $ .. But since string interpolation with this crate still can't be as "spontaneous" (deciding to interpolate a var after starting to write the string) as in other languages (because you have to write s!( in front of the string), maybe it wouldn't make it that much more inconvenient if one had to type {} around even single-var exprs (?) Or maybe this should be a reason to make the interpolation syntax as convenient as possible, to balance out the inconvenience of having to write s!(..) around the string (?) Some people say that Rust is not designed for rapid prototyping and one has to think carefully before writing Rust code. But as someone who uses Rust for everything (incl. web frontends now), I think it makes sense to make Rust more convenient also for rapid prototyping / scripting-like use cases (I also use cargo-script for Rust-based scripts a lot). That's why I think this crate has potential to make Rust for convenient in this area. (Also I wish we could just concatenate strs directly (in native Rust), without having to write .to_string() after the first one.)

I'd also really like to be able to use this with literal-prefix s"..." syntax (which is orthogonal to the interpolation syntax)..

Boscop avatar Jul 27 '18 16:07 Boscop

I chewed on your feedback a bit, and my thinking on it did evolve a bit, including some hesitation. I'm not super swayed by saving a single character, but there are plenty of other languages that use $ syntax, and it is really convenient. Perhaps the biggest objection in my mind is that this is valid rust today:

format!("{foo}", foo=foo)

If I could simply leave off the named argument, I'd have never created this crate. And once we can rename imported macros, it should be as simple as use std::format as s; to get the same brevity. Plus, such a change would automatically support other format specifiers like format!("{foo:?}") to get the Debug` representation. So I'm inclined to move this crate in that direction to build a case for augmenting the existing std library macros.

I did just publish 0.2.0 which uses the {foo} syntax. I'm not calling it final, but I think it's worth at least trying out. I'd be curious to see if you have a strong opinion after using it. I'm even tempted to see if I can just rewrite the macro to actually use format! with named arguments.

anowell avatar Jul 30 '18 08:07 anowell