And thats about it it also makes you include the generic bounds of "?Sized + Trait" on any function you pass it to. The representation is exactly the same. It is not a trait object it is just a plain instance of type A wrapped in a named tuple.
This is the bit that I found a bit odd. &Debug is a trait object, and I kind of get &Wrapper<Debug>, but what is Wrapper<Debug> ?
Does that mean I can take any parametric type, and substitute traits for the type parameters, take a reference, and it becomes a trait object, I guess I find the mechanics of this a little magical and mysterious when compared with Haskell's existential types where a type constraint (trait bound) is always syntacticly a type-class and never masquerades as a type. "forall a . (Debug a) => Ref (Wrapper a)" seems syntactically more clean to me. It also loses some identities, for example how do you write "forall a . (Debug a) => Ref (Wrapper a, Wrapper a)"?
That wasn't my question. I completely understand what struct Wrapper<A:Trait+?Sized>(A) means. The question was what Wrapper<Trait> means given that definition as you also asked in your follow-up:
As far as stebalien@ has described Wrapper<Trait> seems to be just a concept with no binary representation, whereas &Wrapper<Trait> has the binary representation of a trait object fat pointer.
Hence my follow-up question above:
which also relates to your follow-up questions. Still a mystery to me. I would love to understand precisely when &Wrapper<Trait> is allowed for the given definition of Wrapper. E.g. if we defined the Wrapper as a pair:
struct Wrapper<A: ?Sized + Trait>(A, A);
What would &Wrapper<Trait> mean? A tuple of trait objects? Actually, this definition doesn't even compile (playground):
error: the trait `core::marker::Sized` is not implemented for the type `A`
which is not particularly elucidating given that the non-pair version compiles. So there are clearly some constraints, but what precisely?
So &Wrapper2<Trait> has the same representation as &Trait despite the extra tuple field that Wrapper2 contains.
This is really surprising and I don't understand why this was added to Rust. I mean, what's the point of adding the non-reifiable concept of Wrapper<Trait> and a strangely reified &Wrapper<Trait> when one can simply use Wrapper<&Trait> which makes complete sense based on other Rust concepts? In the case where Wrapper<Trait> seems least surprising (the case of a named 1-tuple), &Wrapper1<Trait> has the same binary representation as Wrapper1<&Trait>.
Any insights as to why Wrapper<Trait> (and the &Wrapper<T> as &Wrapper<Trait> conversion) was introduced?
where Ref is a special type constructor unique for each set of trait object bounds. So the fat pointer for both has a pointer to the "Trait" dictionary/vtable and the data which in one case is just the value of type "t' and in the other is the value wrapped with the value-constructors, and in the case of Wrapper2, a tuple with an Int and the value of type "t".
My point was that the representation for both is a fat pointer, which wasn't particularly obvious for &Wrapper<Trait> since nothing like this is defined anywhere. As for whether the representations are identical, I explored this and discovered what I believe a bug in the compiler:
showing that there is clearly an offset in the Wrapped version, but they point to the same vtable. However, I am not able to call the foo method without segfaulting (bug).
@stebalien Since you are already using this concept in your code, could you possibly enlighten me as to how you invoke trait methods on &Wrapped<Trait>?
Specifically, std::mem::size_of::<&Wrapper3<Trait>>() gives 8. But it gives a confusing error, preventing me from creating a &Wrapper3<Trait> object to begin with. So the fundamental question remains: when precisely is &t as &Wrapped<Trait> technically allowed? Only for named tuples where the type-parametrized item is at the end of the tuple?
Thanks for the explanation! The mechanics of the whole Wrapped<Trait> makes more sense to me now and I can see how it might be implemented underneath (modulo the wording of the error for &Wrapped3<Trait>I mentioned above. This feature probably ought to be documented somewhere. Summon @steveklabnik?
Now that you've brought me up to speed, I have a question on your proposal. Specifically, regarding
is it possible to have an unsizedT satisfying these constraints where T is notTrait and Wrapper<T> is valid? A few attempts of mine failed since either (1) I end up getting a sized type or (2) for SubTrait: Trait, &Subtrait is not castable to &Trait to begin with. If there isn't (and there's no danger of it being added in the future), then your proposal seems to make sense.
Thanks, I should have re-read the thread after things clicked for me. Indeed, the unstable Unsize marker trait you discovered does what you want. Perhaps From should be implemented for it, so that you could just do View(self.into()).