At next week’s weekly meeting we will discuss the proposals and implementation
plan for some form of more efficient inheritance.
Background
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.
Agenda
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.
The proposals
-
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 match and 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.
Cheers, Nick