3 ms·
Are there potentially other situations where `&[T + !Sized]` makes sense? The majority of the functions on `&str` seem to make sense for all `&[T + !Sized]` wh
by yazaddaruvala 6y ago
Are there potentially other situations where `&[T + !Sized]` makes sense?
The majority of the functions on `&str` seem to make sense for all `&[T + !Sized]` where `type str = [unsized_char]`.
- steveklabnik 6y agoI don't really know what unsized_char would even mean, chars have a size, and str is not a sequence of chars. That said, I'm also not sure in the general case.
- yazaddaruvala 6y agounsized_char would be some phantom/opaque type that is not actually useable because it represents an object of variable length. e.g. Think of it as an enumeration like : unsized_enum unsized_char { Char1(u8), Char2(u8, u8), Char3(u8, u8, u8), } let c: unsized_char = ...; // is a complied error: “cannot assign a variable stack size.” or something. let parsed: &[unsized_char] = unsafe { /* parse some bytes */}; // this complies because the implementation of some hypothetical &[T + !Sized] appropriately abstracts the allocated memory region. Unlike a normal enum it doesn’t always take 3 bytes of memory, it’s variable memory such that [unsized_char] might only take 1 byte if there is only 1 unsized_char::Char1 inside. Of course this means that you can’t index into the slice because the boundary is not clear. What I’m describing is not different than the internals of str. I’m just trying to armchair design a generic implementation such that str and slice are more unified.
- comex 6y agoYou’re right that what you’re suggesting could work as a way to treat &str as a type of slice, without breaking the type system. But there’s a fatal flaw. If you have `s: &[unsized_char]`, what should slicing, say, `&s[2..4]` do? With the actual `&str`, this treats 2 and 4 as byte indices. But if you’re going to treat str as a slice of a specific type, the indices really should be in units of that type. `&s[2..4]` should return the second and third grapheme clusters, or codepoints, or whatever you want to define `unsized_char` to be. The same applies to `len()` and all the other methods that return or accept indices. But if it’s in units of `unsized_char`, how do you actually implement indexing? You could do an O(n) scan from the beginning of the string, but that’s clearly unacceptable. Or you could set up some kind of acceleration data structure behind the scenes, but that would be expensive to maintain, and would conflict with Rust’s goals of explicitness and cheap FFI. If on the other hand you keep indexing with byte offsets, you end up with almost no operations that work, and do the same thing, for both &[unsized_char] and normal slices. You wouldn’t be able to write any useful generic code that operates on &[T] for T: ?Sized, at least not without branching on which kind of slice it is. And even from a human user’s perspective, the syntactic similarity between two things that work differently could confuse more than it helps. Again, a matter of explicitness.