My current favorite string implementations are the various compact string crates for Rust. Generally, you want a string to be able to do at least three things:
- Pointer, length, capacity tuple, for heap-allocated strings, 24B on x64.
- String inlined into the 24B buffer.
- Pointer, length tuple where pointer points to rodata.
You can do any of that and the discriminator in 24B, given the healthy assumption that all strings are shorter than 2^63.
Sadly, switching costs are massive and every programming language is pretty much struck with the string they started with. Hopefully, whatever comes next can crib from smartstring or compact_str or the like.