If the format!
macro interpolates only identifiers, then in my opinion that feature is worse than useless and shouldn't be stabilized in the language. It's really not a big deal to write format!("{foo}", foo=foo)
, it's not even a big deal to entirely omit those names and rely on automatic indexing. Since Rust isn't Python and requires string literals instead of runtime strings, I simply can't see a situation where one would dump into format!
a string complex enough that named variables and string interpolation are required.
At the very least, for the feature to be useful, I would expect it to support constants, paths and fields. It would also be very jarring if a trivial modification to those cases wouldn't be supported, e.g. if I could write format!("{foo.bar}")
, but not format!("{&foo.bar}")
or format!("{foo.bar[0]}")
.
Once you start supporting those simple enough expressions, it would be more work to special-case the "simple" part than to just allow any expression in interpolation. Ambiguities are very simple to resolve with mandatory whitespace or brackets. For example, if the inner braces denote a block expression
format!("{{foo}}")
then it could be required to written in one of the forms
format!("{ {foo} }")
format!("{({foo})}")
Regarding redability. Yes, complex expressions in string interpolation can easily be unreadable, however the bar for "complex" is very subjective. I seriously doubt that anyone would find this expression unreadable:
format!("{BUF_LEN - 1}")
Anyway, Rust has plenty of ways to make code unreadable. Macros easily make the code impossible to read. Complex nested expressions are also unreadable, and Rust's expression-oriented syntax allows true monstrosities of nested if
's, match
'es, loop
's and tuple constructors.
The way to combat unreadable code doesn't change: don't let it through code review, and implement Clippy lints.
Expressions in format macros are a particularly easy case to fix: an IDE can easily extract the formatted expression into a variable, or even convert an entire format!
call into a form with explicit bindings. This is a trivial job for the proper tooling and it is supported in every language with string interpolation.
As it stands today, the format!
interpolation syntax brings quite a lot of complexity for the most trivial of cases. It also introduces new arbitrary limitations within the language, and an inconsistency with every other language's implementation of that feature. If only variable interpolation is stabilized, then there will be an endles stream of people coming from JS, Python and Kotlin asking how to interpolate more complex expression, because that's the implementation that everyone expects.
It would also introduce an unnecessary footgun into format!
where there was none. If I make a named formatting argument, then it will automatically pick up the value from the closest available scope, even if that was not what I intended and I have just forgotten to set the value in the macro arguments. Currently this case is eaily detected as an error.