@kornel This would be workable, but of course then we need to explain why one literal type allocates while another one doesn’t.
@tibotz As explained before in this thread there are tradeoffs to be made when it comes to string design, if there is an abstraction that lets a programmer have it all, it has yet to be invented.
The string behavior observed in languages such as Java and python (which you seem to be arguing for) is built on the fact that those strings are garbage-collected. Rust has no such concept, and from that basic premise flows a different design. Now, it is possible to abstract over both &str and String with e.g. Cow<str> but that induces a runtime penalty, as explained by an earlier post.
Calls that turn a borrow into an owned value can never be never zero cost.
As for the “syntactic overhead”, that’s the point
The code is supposed to make the reader aware that expensive operations are happening. Rust has a different niche as a programming language than e.g. Python or Java, and it is designed as such. You wouldn’t want to create a kernel in Python/Java, for example. This has to be as possible in Rust as it is in C/C++, and more so where possible.
Trading performance-by-default in favor of convenience seems like the wrong tradeoff for such a language.
I’d say that a language is about abstracting certain things away. What exactly is abstracted by that language depends on the purpose of the language. Rust, for example, is a language that puts performance, safety and concurrency above programmer convenience. When all 4 are possible at the same time, that’s great, and it’ll happily take all 4 into account. But when tradeoffs need to be made, convenience is easily the first thing to go.
That makes Rust in a sense a lower level language than Java (at least when it comes to things like strings), and that’s perfectly fine.