Template Literals ( like JS ) would be nice to have

So I've been using Rust recently and I'm coming to like it, however, I've come to notice that one of the biggest flaws ( at least in my opinion ) is the lack of any templating. I know there is the.format() that looks very ugly and horrible to read.

if I had any suggestion or constructive advice ( whatever that might be worth ), have it something like this.

println!($"hello my name is {name} and i'm {age} years old"). Something like that. Much more elegant than having to do this

println!("Hello, my name is {} and I am {} years old", name, age);
fn main() {
    let name = "Dennis";
    let age = 42;
    println!("hello my name is {name} and i'm {age} years old");
}

Produces:

hello my name is Dennis and i'm 42 years old
2 Likes

println!(), print!(), format!(), ... and all functions using formatting support using variable directly since Rust 1.58 (early 2022). It's just not mentioned in every documentation yet.

3 Likes

Note that it only works with variable names. Not general expression as in JS.

Which I personally find odd-but-good, because my experience seems to indicate that using general expressions within string templates quickly results in an unreadable mess.

4 Likes

Not to mention that Rust expressions are far more powerful. See this reply where I asked about this in a previous thread related to that.

I keep meaning to publish an alternative implementation that does support arbitrary expressions, it's relatively easy to do as a proc-macro, and personally I find that the expanded expressiveness is a net positive when used well (just like all language features, it can be abused, but that's what code reviews are for).

1 Like

What do you plan to do about derive macros embedded into strings? And if that isn't allowed, what rules are there for the expressions that are supported?

IIRC this has been explicitly rejected in the RFC. It's not a matter of lacking implementation, but desire to keep the formatting syntax simple.

https://rust-lang.github.io/rfcs/2795-format-args-implicit-identifiers.html#alternative-solution---interpolation

I see no issues with them, as long as it’s a valid expression it should work (so they’d have to be wrapped into a block to declare any items). I at least would certainly reject a PR hiding an item inside an interpolation though.

My recollection was not that the RFC explicitly rejected this being changed in the future; just that it did not propose doing so initially. (EDIT: and at least the text of the RFC only refers to the authors opinion on the extension, if there was some consensus to reject in the discussion that was not recorded).

1 Like

I'd love to see at least field access expressions supported... I feel like printing fields of structs is very common, and currently there is a somewhat awkward cliff between formatting a local variable and a field.

15 Likes

I'd go slightly further and contemplate any lvalue, for much the same reason as field access.

I feel like allowing * and (...) makes the syntax a bit too noisy given it interacts with format strings and is inside a string literal.

But {a.field.field.field} should of course be subject to the usual auto-deref rules. Then . is really the only new character we have to allow.

1 Like

How about :: to print out constants like i32::MIN?

That's more tricky, I think, with ":" already having special meaning in pattern syntax.

5 Likes

Printing output aside, having a template literal as shorthand for format!("{xyz}") would be handy for constructing Strings.

It does seem out of character for Rust, though, in that it tacitly encourages heap allocation.

Agreed. While we don't want to support arbitrary expressions, extending the syntax to allow field access and array indexing seems fine.

3 Likes

Currently, unless one uses the relevant Clippy lint, Rust gives no particular pressure to use either (panicking) Indexing or get methods that can return Err (edit: :person_facepalming: or, more usually, None), leaving it to the user to decide which to prefer. I'm just a random user, but I would find it unfortunate to change that balance in favor of Index by privileging it in format strings.

1 Like

Valid point, but .get methods typically return Option rather than Result, making it harder to use ? in any context that isn't already returning Option. I can easily imagine allowing ? in this context, but handling an Option in a method that doesn't already return Option requires something more complex than that.

To some extent we already bias towards indexing by giving it the simpler syntax.

1 Like

It seems to me rust should also allow :: in there. Yesterday I needed to format the following (for use in a bug report template):

format!("os={}, arch={}, info={}",
        std::env::consts::OS,
        std::env::consts::ARCH,
        info)

I don't see why that couldn't have been allowed inline.

But isn't your solution easier to read than when you put all these paths inside the string?

1 Like