That's fine, but you'll have to accept that without more details as to what you actually want, this is not happening at all.
Indeed. However, any progress on their part is blocked on questions about what you expect to happen in certain cases. If you cannot explain at least what might happen (not even "should") when your proposed idea is used that satisfies your own goals, I don't know how you can expect anyone else to answer them for you. Again, if this is all you do (and somehow this does get implemented), it'd be frustrating to see "but that's not what I had in mind" if there's some constraint that has to be applied during the implementation.
And yet you can't provide an example of what it looks like before and after and explain the difference? The questions here are not looking for you to answer absolutely everything, but just what you, as the idea originator, are the best person to answer.
All that said, there are a lot of effects here that this idea ends up creating that should really be hashed out up front. Of note (some of which have been asked here):
- Does adding an "impl var" via
impl Trait for T
add a field to every type? - Can a crate change another crate's type by implementing a trait and adding a field?
- How does this affect type layout?
- What the heck happens with an
enum
? - Can I add fields to a ZST? Is it a ZST anymore? What happens to other crates that I depend on (and therefore cannot know about the "impl var") that assume it is (was?) a ZST?
Basically, the core question is:
- Given a type, where does its "impl var" variables live?
If this cannot be answered, this idea is just not implementable. Of course, there are multiple possible answers for this, but they all have tradeoffs. Some off the top of my head:
Modifies the members of the struct
Pros
- Simple in concept.
Cons
- Does not work for types not in the crate (i.e., all top-level types in the
impl
line must be crate-local and non-generic).- Otherwise building becomes undecidable as you need to tell already-compiled crates "oh, this type has additional shadow members you need to consider". Or all types become
DynSized
which makes Rust removes a lot of its zero-cost abstractions.
- Otherwise building becomes undecidable as you need to tell already-compiled crates "oh, this type has additional shadow members you need to consider". Or all types become
- Does not work for
enum
. - Does not work for ZST.
Store in the impl
vtable
Pros
- Works for all types.
- Does not modify the "main" type.
Cons
- Using the trait requires
dyn Trait
to use so that the extra data can have some per-instance place to actually live.- Which means that
ty.uses_impl_var()
is impossible and instead something like(Box::new(ty) as Box<dyn Trait>).uses_impl_var()
is necessary. Note that "impl vars" would somehow have to be initialized inBox::new
which means that traits which have "impl vars" need some additional information forBox
to know about initializing them. Repeat for other containers which supportdyn Trait
in them. - This may mean that "impl var" is required to be const constructible (otherwise
Box::new
is of unknown runtime cost, not just "allocate and move")
- Which means that
- Ambiguities are possible
- Is
self.impl_var
a member of the type or the localimpl
variable of the same name? - Syntactic ambiguity: does accessing an "impl var" require different syntax to make it clear that the access has to happen in some other way?
- What about super-trait "impl vars" of the same name?
- Is
As you can see, even these two (but by no means exhaustive) solutions have considerable downsides. Where you come in is helping to clarify what downsides you prefer (if they are at all acceptable in the first place). Otherwise you may be stuck with something that doesn't match what you actually want and everyone is sadder for it.