At next week’s weekly meeting we will discuss the proposals and implementation plan for some form of more efficient inheritance.
We want some way to have code sharing which is more efficient than traits (in terms of time and space) and more flexible than enums. Our primary use case is the Servo DOM, but we would like this to be more general purpose too. Our constraints are:
- cheap field access from internal methods;
- cheap dynamic dispatch of methods;
- cheap downcasting;
- thin pointers;
- sharing of fields and methods between definitions;
- safe, i.e., doesn’t require a bunch of transmutes or other unsafe code to be usable.
And of course should be as ergonomic as possible, be orthogonal with other library features, feel ‘Rust-y’, etc.
To get an idea of the kind of thing we want to represent (and have an example with which to compare the proposals), see https://gist.github.com/jdm/9900569.
The proposal we have mostly been discussing has been the 'enhanced enum’ proposal (RFC PR #142). First I want to make sure this is the right proposal to be concentrating on. Are any of the other proposals better for Rust? Or are there parts of them we might want to incorporate?
Address any open questions with the selected proposal, or at least identify what the open questions are.
Agree on a staging plan for implementation, in particular what needs doing pre-1.0. And how high priority the other items are.
Enhanced enums (142) (author and champion: nrc)
We discussed this one a fair bit at the work week. The idea is to allow nesting of enums and structs and also for this to not necessarily be lexical nesting (i.e., there is an ‘inherits from’ syntax). Structs are then just an unsized version of enums (they may only be used via pointers and they have minimal size). We then allow virtual methods in impls in order to provide method calls somewhat like traditional OO. Downcasting is given by
match. The side-benefits of this proposal are some unification of enums and structs, enum variants as types, and things like struct variants and enum structs fall out naturally, rather than being weird ad-hoc things.
Virtual Structs (5) (author and champion: nrc)
Stays as closely as possible to single inheritance in Java or C++. Touches only structs so does not unify structs and enums. That means we end up with two design choices (enums or virtual structs). Uses a similar scheme for virtual methods as RFC 142. The advantage of this approach is that it is pretty small and the DOM has a clear encoding. On the other hand, it is pretty much ‘bolted on’ to Rust and not very natural.
Fat objects (9) (author: MicahChalmer; champion: pnkfelix)
Proposes using a pointer to a vtable+data and treating it as DST for representing objects. I use a similar scheme for representing virtual structs in RFC 142. RFC 9 does not actually propose a mechanism for supporting inheritance and efficient virtual methods, just a representation for objects. It suggests using Niko’s earlier [proposal](http://smallcultfollowing.com/babysteps/blog/2013/10/24 /single-inheritance/) for single inheritance by allowing struct inheritance and traits to extend structs. I.e., traits inherit fields from structs.
Extending enums (11) (author: bill-myers ; champion: zwarich)
Proposes combining enums and structs in a similar, but not identical way to RFC 142. Internal nodes are enums, leaf nodes are structs. Introduces
impl ... as matchand
impl ... use ...to handle method dispatch rather than virtual methods in impls. I’m afraid I don’t understand exactly how these work. Efficient virtual dispatch seems to be an optimisation the compiler would do in some circumstances (basically when using an enum within a crate) rather than explicit behaviour, but that probably still satisfies the constraints here. I think this idea will not work without a sized/unsized distinction for enums/structs (maybe I’m wrong). There might be other parts of the proposal we like though.
Trait based inheritance (223) (author: gereeter ; champion: acrichto)
“This is largely based upon #9 and #91, but fleshed out to make an actual inheritance proposal.”. Seems to be lower level than the other proposals, providing building blocks rather than whole solutions. Structs inherit by using the parent struct as a field and using an attribute to force it to come first in the runtime layout. Adds traits to manually extend coercions and subtyping. Fat pointers are made thin by storing the vtable info in the struct manually and more traits to implement for casting. This proposal is more flexible, but also more boilerplate-prone than the other.
Kimundi and eddyb have promised an RFC for a possible solution using trait fields. WIP RFC - https://etherpad.mozilla.org/RrQ24kMxz0. Encoding of jdm’s example: https://gist.github.com/eddyb/69e4d2c14c3610f14ea3. TODO - we should assign someone to champion this.