Why can't String be made obsolete?

So here is a quick question I was wondering...
why can't String be made obsolete in favor of str and &str?

then we could have mut str and mut &str which would be the equivalent of a String.

I don't intent this to be made a discussion I was just wondering why something like that wasn't done

Why do you think this will be an equivalent replacement?

I'm sure it wouldn't be without special cases in the compiler, but the idea would be it implicitly converts between a c string and a c++ string depending on context like mutability and whether its reference while providing the same interface

Because String owns its data while &str/&mut str does not own data, but has to borrow from some other types which do own their data, e.g String.

Sometimes we do need ownership.

PS: it is &mut str not mut &str.

For Your changing in the main thread:

str is DST, which you cannot construct and use the value directly


oh my mistake.
anyways borrowing doesn't need a new type does it?

I guess you are asking for preferring Box<str>/&str/&mut str and making String obsolete?

But String can grow, while str cannot.


@oooutlk maybe. also isn't that the definition of immutability?

Edit: I would think rust actually has a good memory management system for something like this.
you would no longer need to worry about allocated String types behind the compiler after implicit conversion.

Any such implicit conversion is a no-go for system language, unless there's a real big ergonomics improvement for relatively small runtime cost (i.e. implicit dereferencing).

1 Like

Oh no I don't expect something like std::StringBuffer in Rust 2027 after automatic memory management for strings have been introduced in Rust 2024.

I'll note that the split between str and String seems to be pretty fundamental. Even in things like Java and C# you have the difference between String and StringBuffer.


I guess you could have a Cow-like structure that automatically converts between a borrowed and owned string as needed. However that doesn't really remove the distinction, it just (mostly) hides it behind a layer of abstraction.


This one sentence goes against at least these points of the rust philosophy:.

  1. You always need to keep an eye on allocation, ownership, and borrows. Often this is reduced to a trivial amount of work, but the code assumes you'll do that regardless of the amount of work.
  2. Almost no implicit conversion is done in Rust. It's often a source of bugs. In general Rust favors explicit code over implicit code, in order to keep written code not just readable but understandable.

That would be absolutely horrifying, and open a rather large door to buffer overflows, especially for C-style '\0'-delimited strings.


No, we couldn't. They are completely different mechanisms. String is an owning, allocating type, whereas str is a temporary view into another String allocated somewhere else, or even a subslice of another str. These simply can't be unified because they do different things and solve different problems.


I guess the C++ equivalent is String (for String) and std::string_view (for str).

Except the Rust str takes care of all the dangling reference problems one can run into in C++. And the Rust String understands unicode where as the C++ String does not.

C does not even have a string type.

string_view is more like &str. C++ doesn't (AFAIK) have any way to express types like Rc<str> or Arc<Mutex<str>> Arc<str>, which in Rust are the straightforward application of regular type constructors to the unsized type str.

Good luck constructing a value of this type though…

Well, okay, that particular one isn't terribly useful anyway, but you could if you really wanted to. :smile:

hmm, are you sure? I haven’t found a way of obtaining a Arc<Mutex<str>> yet without UB, perhaps I’m missing something…

E.g. transmuting from a Arc<Mutex<[u8]>> should/might be UB because Arc and ArcInner and Mutex are all repr(Rust). Edit: I guess the Arc problem can be avoided with from_raw/into_raw, but I see no way around the Mutex

Hmm... you might be right, I don't have the patience to fiddle with it at the moment but the obvious route would be technicallyÂą UB, that's true. I think at least the Arc<UnsafeCell<str>> version could work, since UnsafeCell is repr(transparent).

Âą As I've mentioned before, although Rust makes no explicit guarantees about the layout of generic types that may be unsized, the fact that unsizing coercions exist effectively proves that the layout is in fact the same between different generic instantiations. IMO that guarantee should actually just be formalized, since we know it can't plausibly be false and it is already used extensively in std with no justification. But this suggestion was shot down last time I mentioned it, and I'm not prepared to die on that hill.