I sort of like the idea of using extern type for this; that seems to avoid the unsized type syntax that I was floating before.
One thing that is part of these traits is what type of non-meta data is expected, right? At least for things like DynSized, the Meta presumably imposes some conditions on what it can be combined with, but those are kind of implicit. That’s maybe OK, just interesting.
I like the Thin<T> setup, that seems elegant, though clearly for any particular dynamically sized type, one could make it thin as well. e.g., it seems relatively straighforward to satisfy @withoutboats’s use case from failure, right?
I definitely agree that the cognitive costs of ?Traits are problematic. I think that the idea of having a “family” of Sized-related traits helps somewhat here, where picking one from that family kind of disables the others, helps somewhat here; it’s not a complete solution (but there may not exist a complete one).
More specifically, one problem I experienced when we were discussing ?DynSized was that it was very hard to talk in “negative” terms – it feels like your proposal helps here somewhat. As an example, just look at this list:
-
T – size known statically
-
T: ?Sized – size known dynamically
-
T: ?DynSized – size not known at all
It’s logical, but it feels somehow weird to say “in order to have a type T whose type is known dynamically, I say that it is not known statically.” The idea of making T: DynSized helps here, for sure.
(By the way, how under this proposal does one do the equivalent of T: ?DynSized? Oh, I guess T: Referent?)
Another thing I’ve found quite annoying in practice with ?Sized bounds is that they must be repeated so commonly, at every point. For example:
struct Foo<T: ?Sized> { }
impl<T: ?Sized> Foo<T> {
fn compare<U>(&self, other: &Foo<U>) { ... }
}
See the problem? Oh, right, I need U: ?Sized in compare … =) This part is not helped by your proposal, of course. e.g., I would presumably have to write T: DynSized at each spot there.
(And of course there is the weirdness that adding bounds makes the type match more types — but even though that doesn’t make sense when you think hard about it, I do think it could feel more natural overall. Typically, adding bounds gives you more capabilities – and here it’s giving you the “extra” ability to work with types like [T]. Of course, it’s only when you think hard that you realize this “extra” ability is something the caller gets, not the callee as usual. But it’ll matter to stuff like semver guidelines.)
I am still interested in seeing if we can “rephrase” these concepts to connect them to ownership and borrowing. In particular, it feels very “significant” to me that T: Referent / T: ?DynSized basically corresponds to a non-owned T.