Summary of efficient inheritance RFCs

From @eddyb and @Kimundi’s proposal: “People coming from other mainstream languages are usually familiar with type inheritance, which will make them overuse this feature in places where a trait-based design would be the better choice.”

I couldn’t agree more. Your average user will get more out of rust of inheritance is not easily available. Orthogonality with existing features should be the first priority, and ergonomics might even be considered a bad thing.

Also, there seems to be equal, if not more, interest in the performance characteristics of C++'s implementation of inheritance than the expressitivity gained from the language feature itself. This makes me thing the true solution is in fact some fancy system for existential types. Regardless, a proposals that doesn’t offer enough control over the runtime representation, may the miss the mark or even do more harm than good.

The more low-level proposals (@MicahChalmer’s, @eddyb and @Kimundi’s) gave us maximal control over the runtime representation, maximal orthogonality, and minimal ergonomics, and minimal change to the language, so I think they are a clear win. (They seem pretty reconcilable too.)

2 Likes

RFC 91 together with a few standard macros seems, to me, to be an elegant solution. I particularly like that the Coercible and HasPrefix traits provide a means to generalise type relations.

A pattern I’d like to praise is the use of structs with single fields (or newtypes), for safety and for clarity. From the RFC:

pub struct Age {
    pub age: uint
}

Being able to convert a HashMap<K, Age> to a HashMap<K, uint> impressed me.

Note that RFC 223 contains (and presumably subsumes) the ideas from RFC 91.

1 Like

I have another proposal: https://github.com/rust-lang/rfcs/pull/245. This takes the nice bits from #142 (enhancement and ‘unification’ of structs and enums), but uses traits for virtual dispatch rather than a custom system around concrete impls.

@eddyb and @Kimundi’s proposal is up: RFC PR 250: Associated field inheritance.

This is the only proposal that invoked the following initial reaction from me: “Yes.”

This proposal basically extends various aspects of traits to handle inheritance, but at the same time the components in this RFC doesn’t feel like bolted on specially for inheritance support, and each is useful in its own right even without a need for (full) inheritance. Their inclusion in the language can be very natural in my opinion.

And most importantly, I don’t think people will have a tendency to overuse inheritance with this RFC, or rather, there is still only one true way of method dispatch - traits, so use of inheritance doesn’t confilict with the current Rust style.

This is currently my favourite proposal.

3 Likes

As a newbie to Rust, that syntax looks pretty scary to me. The whole struct HTMLImageElement { vtable: Vtable<Element, HTMLImageElement> ...} feels like needless boilerplate. C++ syntax struct HTMLImageElement: public Element looks better by comparison.

1 Like

The Vtable and friends are basically a “low-level” way to do a performance optimization, as long as this is made possible, we can have macros/attributes that are nice looking and easy to use for expressing this. Also, this way, normal code that doesn’t need C++ style internal vtables are not affected and works like today.

My first reaction, rather than “yes”, was “uhhhhhhh let me read that again?”

It would definitely be better if Vtable were relegated to library code like the implementation of Fat and never needed in actual inheritance hierarchies.

The struct HTMLImageElement : Element syntax might even be a good way to implement associated fields, although it would break the intersection of associated fields and FFI struct layout.

To be clear I’m complaining about syntax. With enough sugar I could quite enjoy this type of inheritance.

This may sound weird, but I like the fact that inheritance is difficult/“ugly” to use, because it makes people less likely to choose to use it rather than generics and traits.

1 Like

It does sound weird. Naturally, a language design that makes code ugly or difficult to write – and therefore to read – is the worst possible language design. It’s a failed design. Good design allows you to express your ideas using a small subset of orthogonal constructs without ambiguity or redundancy.

We already have a good design, they are traits. Making inheritance difficult to use in Rust shows that we don’t want you to use it except if you are certain that there are no other solution.

1 Like

I worried about this too. But this problem doesn’t quite exist when inheritance is based on traits. C++ has this problem because its template/concept system is completely bolted onto the object system. But Rust can unify all of them into the enhanced traits, of which RFC PR 250 is the most seamless IMHO. RFC PR 223 takes more of a “building blocks” approach and do not directly enhance (normal) traits (the author is planning to adopt parts of PR 250, it seems).

I believe the good bits of several RFCs can be combined to form a satisfying solution which is flexible and hard to misuse.

I have good faith in the Rust community and this discussion. A good solution will be found that is pleasant, performant, hopefully derives advantage from the trait system.

I have yet another RFC: Layout Inheritance

It’s based on an idea from this issue that never really made it into an RFC on its own, which is one of the simplest versions that’s still nice and orthogonal.

I have made quite a few changes to the RFC based around enhancing enums and adding implementation inheritance. I would like to tell the story of this RFC in parts (I’ve done this in the RFC summary in more depth):

*make Rust data structures more powerful, more orthogonal, and more unified. This includes data inheritance which, in keeping with the data/behaviour separation in Rust is totally separate from trait inheritance/implementation.

*Add behaviour inheritance which follows data inheritance when implementing a specific trait. I hope this feels natural as a way to share behaviour between related data types.

*Offer optimisations for speed and space using the closed and unsized annotations.

I hope that this addressed the two big (concrete) criticisms of earlier proposals about the near-unification of enums and structs, and the inheritance in trait-less impls.

Can RFC PR 250 (kimundi and eddyb’s proposal) be linked into the OP with the others?

You’re not supposed to use it unless you really know what you’re doing, and then it’s an opt-in layout optimization that sacrifices flexibility for some domain-specific gains. It’s not a kind of “inheritance”, and I would compare its “user friendliness” to #[repr(C, packed)].

It’s not intentionally ugly or obtuse, but rather verbose: clearly stating your intent to change the representation of trait objects of a given trait to “thin pointers”, forcing single inheritance chains in the trait hierarchy (which does not limit it to single inheritance relations everywhere, btw). The mechanism could be extended in the future to allow C++, COM or Objective-C interop. The Vtable primitives seem complicated because they use type safety to avoid requiring unsafe code.

You still need to ‘sell’ it to Gecko people. If it’s that verbose, I fear it will turn them off.