# Pre-RFC: Disjoint Polymorphism

**URL:** <https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029>\
**Category:** language design\
**Created:** [May 14, 2015, 1:08pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029 "2015-05-14T13:08:00Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![matthieum](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matthieum/32/4023_2.png) [@matthieum](https://internals.rust-lang.org/u/matthieum)\
**Post date:** [May 14, 2015, 1:08pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/1 "2015-05-14T13:08:01Z")

</div>

> **This Pre-RFC now lives on github, where it easier to make it evolve:** [rust-poly/doc/0000-disjoint-polymorphism.md at master · matthieu-m/rust-poly · GitHub](https://github.com/matthieu-m/rust-poly/blob/master/doc/0000-disjoint-polymorphism.md)

> **Last edited 2015-05-15 (9 posts in the thread), see Change Log at the end**

I have followed the various RFCs for adding "inheritance" in the language (as defined by Servo's extended requirements), but their invasive nature always bugged me.

I very much appreciate the disjoint nature of Rust's `trait` and `struct`, which neatly separate _payload_ from _behaviour_. It is ultimately more flexible than the traditional OO-like code. Servo's requirements add a new dimension _usage_, but unfortunately most existing RFCs (as referenced in [Summary of efficient inheritance RFCs](https://internals.rust-lang.org/t/summary-of-efficient-inheritance-rfcs/494)) seem to end up mixing those properties. A notable exception is [Fat Object](https://github.com/rust-lang/rfcs/pull/9), and this RFC turned out somewhat similar to it.

I have thus tried to take a stab at it, and I am satisfied enough with the current production that here I am solliciting feedback.

Alright, enough talking.

_Note: if you are looking for a revolution, you are going to be thoroughly disappointed; an explicit goal was to integrate seamlessly in the language and after several iterations I ended up with a mostly-library solution. I believe it to be a good thing._

_Note: this RFC is fairly long, at over 35,000 characters, the impatient can look for the DOM word to get a quick feel of it._

* * *

- Start Date: (fill me in with today's date, YYYY-MM-DD)
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)

# Summary

Solving the Servo DOM design requirements (and beyond), while integrating smoothly with the already existing `trait` mechanism.

This RFC provides:

- Data Polymorphism
- Trait Polymorphism
- Thin Polymorphic Pointer/References Support
- Runtime Type Information (to handle safe down-cast)

# Motivation

Rust currently supports polymorphism through its traits, however the experience in Servo has raised a number of requirements which are not fulfilled.

A summary of those requirements is given here:

- cheap field access from internal methods;
- cheap dynamic dispatch of methods;
- cheap down-casting;
- 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;
- syntactically lightweight or implicit upcasting;
- calling functions through smartpointers, e.g. fn foo(JSRef, ...);
- static dispatch of methods.

There have already been a number of proposals (see [Summary of Efficient Inheritance RFCs](https://internals.rust-lang.org/t/summary-of-efficient-inheritance-rfcs/494)).

This RFC is similar in nature to [Fat Objects](https://github.com/rust-lang/rfcs/pull/9) and tries not to focus on building independent bricks, but instead focus on maximizing integration with the existing code and avoid splitting the Rust landscape into two incompatible run-time polymorphism paradigms, which would hurt re-usability.

This RFC thus designs two disjoint polymorphism paths (one for data, one for interfaces), and a couple core `struct`s to bridge the two, giving ad-hoc inheritance to those who wishes it in manner that let them use all pre-existing `struct`s, `trait`s and functions defined around them. Likewise, the `struct`s and `trait`s they create can be used without "inheritance".

It manages to do so with minimal compiler support, thus opening the door to other library schemes.

# Detailed design

This RFC is rather long, as there is a lot to cover, and therefore it is separated in multiple subsections, each building (potentially) upon the precedent. Some sections (or parts) could potentially be used independently of the others.

In keeping with Rust tradition, this RFC preserves the orthogonality of defining data structures (in `struct`) and defining interfaces (in `trait`). By doing so, it maximizes the opportunity to mix and match "object-like" polymorphism and trait polymorphism.

_As usual, all names are subject to discussion._

## Transmutable, Coercible, Convertible

First things first, let us introduce a couple terms.

### Transmutable

A type `U` is said to be transmutable to a type `T` if the compiler allows `std::mem::transmute` to convert from `U` to `T`. Doing so might lead to undefined results, of course, which is why the method is `unsafe`.

As an example, `Box<T>` is transmutable to `*const T`, irrespectively of whether it is sensible to do so or not.

This relationship is (probably) symmetric.

### Coercible

A type `U` is said to be coercible to a type `T` when transmuting `U` to `T` "works". This is voluntarily vague, and sufficient for this RFC.

As an example, `&str` is coercible to `&[u8]`, however the reverse is not true since not every byte sequence is a valid UTF-8 sequence.

This relationship is therefore asymmetric. It is also transitive.

The following intrinsic traits `core::mem::{Coerce<T>,CoerceRef<T>,CoerceRefMut<T>}` are introduced to allow querying this relationship:

```rust
unsafe trait Coerce<Target> {
    fn coerce(self) -> Target { mem::transmute(self) }
}

unsafe trait CoerceRef<Target> {
    fn coerce_ref(&self) -> &Target { mem::transmute(&self) }
}

trait CoerceRefMut<Target>: CoerceRef<Target> {
    fn coerce_ref_mut(&mut self) -> &mut Target { mem::transmute(&mut self) }
}

```

The following blanket implementation is provided too:

```rust
unsafe impl<A, B> CoerceRef for A
    where A: Coerce<B>
{
}

```

It is expected that the compiler then allows implicit coercion from `A` to `B` when `A: Coerce<B>`, from `&A` to `&B` when `A: CoerceRef<B>` and from `&mut A` to `&mut B` when `A: CoerceRefMut<B>`.

> Note: if the compiler chases down coercions (as they are transitive) it must take care to avoid running in circles.

> Note: mutability references allow modifying the inner part and therefore while `str: CoerceRef<[u8]>` is viable, `str: CoerceRefMut<[u8]>` is not because it would allow mutating individual bytes and the resulting `str` would not necessarily hold a valid UTF-8 sequence.

### Convertible

A type `U` is said to be convertible to a type `T` if there exists a valid transformation from `U` to `T`.

As an example, `'a String` is convertible to `&'a str`, however the reverse is not true as while a `String` could be produced it would not necessarily have the lifetime `'a`.

This relationship is therefore asymmetric. It is also transitive.

## Data Polymorphism

Data Polymorphism concerns itself in making it possible to safely access part of a `&U` via a `&T`.

### Syntax

Grammar:

```rust
struct StructName: [pub] StructName (+ [pub] StructName)* {
    // other attributes
}

```

Example:

```rust
struct FirstParent;

struct SecondParent {
    a: int
}

impl SecondParent() {
    fn increment(&mut self) { self.a += 1; }
}

struct Child: FirstParent + pub SecondParent {
    // other attributes
}

fn usage(d: &Child) {
    d.increment(); // calls SecondParent::increment()
    println!("{}", d.a);
}

```

### Semantics

By deriving from another `struct`, the derived `struct` embeds its parents' fields. However, due to encapsulation, it can only access fields that it could access if the parent was an attribute.

In essence, the previous example could be rewritten:

```rust
struct Child {
    _super_first: FirstParent, // 0 bytes, but mentioned anyway
    pub _super_second: SecondParent,
    // other attributes
}

fn usage(child: &Child) {
    d._super_second.increment();
    println!("{}", child._super_second.a);
}

```

### Guarantees

In addition to the syntactic sugar, a number of guarantees are made:

- `Child` is said to derive from `Parent` if `Parent` is an immediate of `Child` or if any base of `Child` derives from `Parent`.
- `&Child` is convertible to `&Parent`, if `Child` derives from `Parent`.
- `&Child` is coercible to `&Parent`, if `Child` derives from `Parent` and `Parent` is an empty `struct`.
- `&Child` is coercible to `&Parent`, if `Child` derives from `Parent` and `Parent` is the first non-empty base of `Child`.
- `&Child` is coercible to `&Parent`, if, `T` being the first non-empty base of `Child`, `&T` is coercible to `&Parent`.

For ease of use, the compiler should perform implicit upcasts as necessary, either to access the fields or methods of the `Parent`. Down-casts will be dealt with in a later chapter.

As shown in the semantics section, `pub` affects whether a parent is publicly exposed or not. `&Child` is only safely coercible to `&Parent` in a given lexical scope if that relationship is accessible from this scope.

> Note: the compiler should automatically implement the `Coerce` and `CoerceRef` traits, when it makes sense, between `Parent` and `Child`. It should never, however, implement the `CoerceRefMut` trait on its own as it might allow violating some of the child invariants (which need be stricter than the parent per the Liskov's substitution principle); this implementation is left to the user.

### Common Ancestor

This RFC defines that `()` (the unit type) is a common ancestor to all `struct`:

- For any `T`, `&T` is coercible to `&()`.
- `()` being an empty `struct`, it does not prevent coercibility to any other parent.

### Disambiguation

If an ambiguity arises due to conflicting field names or method names, disambiguation requires explicitly casting to the appropriate reference type or simply naming the parent:

```rust
fn usage(child: &Child) {
    SecondParent::increment(child);
    println!("{}", (child as &SecondParent).a);
}

```

## Trait Polymorphism

Trait Polymorphism concerns itself in making it possible to safely access part of the interface of a `&U` via a `&T`.

### State of the art

This is already possible in Rust today:

```rust
trait FirstBase {
    fn first_method(&self);
}

trait SecondBase {
    fn second_method(&self);
}

trait Derived: FirstBase + SecondBase {
    fn derived_method(&self);
}

```

### Static Dispatch

> FIXME (2015-05-15): this section may still require a review

It is possible to guarantee static dispatch of a `trait` method, by explicitly selecting the `enum` or `struct` for which it was implemented.

For reminder:

```rust
struct Child: FirstParent, SecondParent { ... }

```

```rust
impl FirstBase for FirstParent { ... }
impl Child {
    fn first_method(&self);
}

fn doit(child: &Child) {
    <Child as FirstBase>::first_method(child);
}

```

A more complicated case may imply also having a `struct` ambiguity, it is resolved similarly:

```rust
impl SecondBase for FirstParent { ... }
impl SecondBase for SecondParent { ... }
// Note: SecondBase not implemented for Child

fn doit(child: &Child) {
    <SecondParent as SecondBase>::second_method(child);
}

```

### Trait implementation re-use

Much like a `struct` may access its parent's field or method unambiguously, so may a `trait`.

By default, should a parent of a `struct` implement a `trait`, it is not necessary for the `struct` to implement any method, though it still has to explicitly declare the `trait` implementation:

```rust
impl FirstBase for FirstParent {
    //
}

impl FirstBase for Child {} // automatic, re-use FirstParent's implementation

```

In the case that multiple parents of a `struct` could provide the `trait` implementation, then the implementation requires disambiguation. A manual implementation must be provided, it may delegate using Static Dispatch as appropriate:

```rust
impl FirstBase for Child {
    fn first_method(&self) {
        <SecondParent as FirstBase>::first_method(self);
    }
}

```

A macro could be provide to perform the boring job of forwarding the arguments appropriately, although this case should probably be rare enough in practice that it might just no be worth it.

## `core::rtti`

In order to provide all the necessary functionality, a new module is introduced: `core::rtti`, re-exported as `std::rtti` as part of the std facade.

### `TypeInfo`, `VTable` and `VRef`

The intrinsic types `core::rtti::{TypeInfo,VTable}` and the library type `core::rtti::VRef<Trait>` are introduced:

```rust
struct TypeInfo {
    size: usize,
    align: usize, // Note: log2(align) could be packed in unused bytes of size.
    trait_id: TypeId,
    struct_id: TypeId,
    // ... others ?
    down_cast_trait: fn (TypeId) -> Option<&'static VTable>,
    down_cast_struct: fn (TypeId) -> bool,
}

struct VTable {
    type_info: &'static TypeInfo,
}

struct VRef<Trait> {
    vtable: &'static VTable,
}

impl<Trait> VRef<Trait> {
    fn get_type_info(&self) -> &'static TypeInfo;

    fn drop(&self, it: &mut ()) {
        unsafe {
            // only valid for below layout on x86/x86_64 
            let vptr = self.vtable as *const isize;
            let drop = vptr.offset(1);
            let drop: fn (&mut ()) -> () = mem::transmute(*drop);
            drop(it)
        }
    }

    fn get_vtable(&self) -> &'static VTable;

    // ...
}

```

The methods of the `VTable` are not explicit mentioned because their number depends on the particular trait being implemented, so instead a raw memory layout similar to the following is expected:

```rust
trait A: Clone + B + E {}
trait B { fn bar(&self); }
trait E {}

//
// Memory Layout of the VTable of A
//
// Each cell [n] represent a pointer-sized memory cell (on x86/x86_64)
// where n is the compile-time index giving access to its content.
//
// VRef<A> VRef<Clone> VRef<B> VRef<E>
// | | | |
// +-+ +-+ | +-+
// [0] VTable (A) + + + + | + +
// + + + + | + +
// [1] Drop::drop + + + + | + +
// + + + + | +-+
// [2] Clone::clone + + + + |
// + + + + |
// [3] Clone::clone_from + + + + |
// + + +-+ +-+
// [4] VTable (B) + + + +
// + + + +
// [5] Drop::drop + + + +
// + + + +
// [6] B::bar + + + +
// +-+ +-+
//
// Both VTable (A) and VTable (B) refer to TypeInfo (A).
//

```

The following guaranteed are made:

- `VRef<Derived>` is convertible to `VRef<Base>` if `Base` is a super-trait of `Derived`.
- `VRef<Base>` is dynamically convertible to `VRef<Derived>` if `Base` is a super-trait of `Derived`, the conversion may fail if the current object does not implement `Derived` though.
- `VRef<Derived>` is coercible to `VRef<Base>` if `Base` is an empty trait.
- `VRef<Derived>` is coercible to `VRef<Base>` if `Base` is the first non-empty super-trait of `Derived`.
- `VRef<Derived>` is coercible to `VRef<Base>` if, `T` being the first non-empty super-trait of `Derived`, `VRef<T>` is coercible to `VRef<Base>`.

> The design of `TypeInfo` and `VTable` was done with simplicity in mind, as a proof of concept. Their final implementation might varied wildly depending on target architecture, compilation options and benchmark results.

### `Class` and `DynClass`

The library types `core::rtti::{Class<Trait, Struct>, DynClass<Trait, Struct>}` are introduced:

```rust
#[repr(C)] // Need to ensure layout compatibility with DynClass
struct Class<T, S>
    where S: T
{
    vref: VRef<T>,
    data: S,
}

#[repr(C)] // Need to ensure layout compatibility with Class
struct DynClass<T, S> {
    vref: VRef<T>,
    data: S,
    _: [u8], // Attempt to prevent `DynClass` from being accidentally used by value
}

impl<T, S> DynClass {
    fn as_trait(&self) -> &T;
    fn as_trait_mut(&mut self) -> &mut T;
    fn as_struct(&self) -> &S;
    fn as_struct_mut(&mut self) -> &mut S;
}

```

It should be noted that a `Class` is just a package and does not in itself allow any polymorphism. Polymorphism is delegated to `DynClass`, which can be created from a `Class`:

- `Class<T, S>` is convertible to `DynClass<T, S>`
- `&Class<T, S>` is coercible to `&DynClass<T, S>`
- `&mut Class<T, S>` is coercible to `&mut `DynClass\<T, S\>`

`DynClass` itself implements type erasure and thus offers polymorphic behaviour. Based on the coercible properties of `VRef` and `struct`, we get:

- `&DynClass<D, C>` is coercible to `&DynClass<B, C>` if `VRef<D>` is coercible to `VRef<B>`.
- `&mut DynClass<D, C>` is coercible to `&mut DynClass<B, C>` if `VRef<D>` is coercible to `VRef<B>`.
- `&DynClass<D, C>` is coercible to `&DynClass<D, P>` if `&C` is coercible to `&P`.
- `&mut DynClass<D, C>` is coercible to `&mut DynClass<D, P>` if `&mut C` is coercible to `&mut P`.

> Note: unlike `Class`, `DynClass` does not require that `S` implements `T`. This is intentional, it allows flexibility in the coercion of references. It is still safe because it can only be created from `Class` so that the actual type stored (most-derived type) does implement `T`.

### `Dyn`

While one can always use `()` as a common ancestor in the above types, this RFC introduces a few type aliases `core::rtti::Dyn<Trait>` as a short-hand.

```rust
type Dyn<T> = DynClass<T, ()>;

```

### `DownCast`, `DownCastRef` and `DownCastRefMut`

In order to control down-casts, the traits `core::rtti::{DownCast<Target>, DownCastRef<Target>, DownCastRefMut<Target>}` are introduced.

```rust
trait DownCast<Target> {
    fn down_cast(Self) -> Result<Target, Self>;

    unsafe fn unchecked_down_cast(Self) -> Target;
}

trait DownCastRef<Target> {
    fn down_cast_ref(&Self) -> Option<&Target>;

    unsafe fn unchecked_down_cast_ref(&Self) -> &Target;
}

trait DownCastRefMut<Target> {
    fn down_cast_ref_mut(&mut Self) -> Option<&mut Target>;

    unsafe fn unchecked_down_cast_ref_mut(&mut Self) -> &mut Target;
}

```

The `unsafe` functions are provided for speed, they performs the necessary runtime adjustments (if any) without checking whether the down-cast is valid or not.

On the contrary, the safe functions perform the check, and indicate the cast failure thanks to their more elaborate return type.

> Note: there is no blanket implementation of `DownCastRef` or `DownCastRefMut` based on `DownCast` because the latter allow more operations (offset adjustments) than the former.

### Casting

It would be better if the compiler could perform the up-casts implicitly, much like with `Deref`, there seems to be little point in having the user fiddling with `as` over and over.

The type `DynClass` implement the `DownCast` and `Coerce` traits as necessary.

```rust
impl<T, S> Drop for DynClass<T, S> {
    fn drop(&mut self) {
        unsafe {
            let data: &mut () = core::mem::transmute(&mut self.data);
            self.vref.get_type_info().drop(data);
        }
    }
}

unsafe impl<T, S, B, P> Coerce<Box<DynClass<B, P>>> for Box<DynClass<T, S>>
    where VRef<T>: Coerce<VRef<B>>,
          S: P, S: CoerceRef<P>
{
}

unsafe impl<T, S, B, P> CoerceRef<DynClass<B, P>> for DynClass<T, S>
    where VRef<T>: Coerce<VRef<B>>,
          S: P, S: CoerceRef<P>
{
}

impl<T, S, B, P> CoerceRefMut<DynClass<B, P>> for DynClass<T, S>
    where VRef<T>: Coerce<VRef<B>>,
          S: P, S: CoerceRefMut<P>
{
}

impl<T, S, D, C> DownCast<Box<DynClass<D, C>>> for Box<DynClass<T, S>>
    where D: T,
          C: S, C: CoerceRef<S>
{
    // ...
}

impl<T, S, D, C> DownCastRef<DynClass<D, C>> for DynClass<T, S>
    where VRef<D>: Coerce<VRef<T>>,
          C: S, C: CoerceRef<S>
{
    // ...
}

impl<T, S, D, C> DownCastRefMut<DynClass<D, C>> for DynClass<T, S>
    where VRef<D>: Coerce<VRef<T>>,
          C: S, C: CoerceRefMut<S>
{
    // ...
}

```

### Interaction with `Box`, `Rc`, ...

There is no built-in way in `Box::new` to select the desired size and alignment, so dedicated helper functions should be provided to convert in and out of `DynClass`:

```rust
use core::mem;

fn make_dynamic<T, S>(original: Box<Class<T, S>>) -> Box<DynClass<T, S>> {
    unsafe { mem::transmute(original) }
}

fn make_static<T, S>(original: Box<DynClass<T, S>>) -> Result<Box<Class<T, S>, Box<DynClass<T, S>>> {
    let allowed = original.vref.get_type_info().trait_id == TypeId::of::<T>() &&
                  original.vref.get_type_info().struct_id == TypeId::of::<S>();

    if (allowed) { Ok(mem::transmute(original)) }
    else { Err(original) }
}

fn up_cast<T, S, B, P>(original: Box<DynClass<T, S>>) -> Box<DynClass<B, P>>
    where T: B, S: P, S: CoerceRef<P>;

```

## Sanity Check

Let us verify how each of the requirements were addressed in this RFC.

- cheap field access from internal methods
  - provided via monomorphization (of `trait` methods) or via `&Struct` conversions.

- cheap dynamic dispatch of methods
  - the call is performed like with regular traits, this RFC only changes the packaging.

- cheap down-casting
  - down-casting to the most-derived trait/struct may be cheap, a simple comparison of `TypeId`.
  - down-casting to an intermediate trait/struct may be slightly more costly, as a few more comparisons will be necessary.

- thin pointers
  - provided, though lack of integrated support make them slightly awkward.

- sharing of fields and methods between definitions
  - provided by `struct` and `trait` polymorphism.

- safe, i.e., doesn't require a bunch of transmutes or other `unsafe` code to be usable
  - `unsafe` will be present in the `core` library, however user code should not need it, though some checks bypass are so provided.

- syntactically lightweight or implicit upcasting
  - it is expected that the compiler will perform the upcasting by itself (through tight integration of `Coerce` and `CoerceRef`), otherwise calling the methods will be necessary.

- calling functions through smart pointers, e.g. fn foo(JSRef, ...)
  - through `Deref`

- static dispatch of methods
  - provided by the regular procedural syntax call (see Static Dispatch)

## Implementing the DOM according to requirements

Let us now how an example of a simple DOM would look like given those facilities, as it is the reference example used by the existing RFCs.

```rust
trait Node {}

struct NodeData {
    parent: Rc<DynClass<Node, NodeData>>,
    first_child: Rc<DynClass<Node, NodeData>>,
}

impl Node for NodeData {}

struct TextNode: NodeData {
}

impl Node for TextNode {}

trait Element: Node {
    fn before_set_attr(&mut self, key: &str, val: &str) { ... }
    fn after_set_attr(&mut self, key: &str, val: &str) { ... }
}

struct ElementData: NodeData {
    attrs: HashMap<String, String>,
}

// Note: private access to ElementData::data, ensuring invariants;
// also, this method is always statically dispatched and thus inlinable.
impl ElementData {
    fn set_attribute(&mut self, key: &str, value: &str) {
        self.before_set_attr(key, value);
        // update
        self.after_set_attr(key, value);
    }
}

impl Element for ElementData {}

struct HTMLImageElement: ElementData {
}

impl Node for HTMLImageElement {}

impl Element for HTMLImageElement {
    fn before_set_attr(&mut self, key: &str, val: &str) {
        if key == "src" {
            // remove cached image
        }
        <ElementData as Element>::before_set_attr(key, value);
    }
}

struct HTMLVideoElement: ElementData {
    cross_origin: bool,
}

impl Node for HTMLVideoElement {}

impl Element for HTMLVideoElement {
    fn after_set_attr(&mut self, key: &str, value: &str) {
        if key == "crossOrigin" {
            self.cross_origin = (value == "true");
        }
        <ElementData as Element>::after_set_attr(key, value);
    }
}

fn process_any_element<'a>(element: &'a DynClass<Element, ElementData>) { ... }

fn main() {
    let video_element: Rc<Class<Element, HTMLVideoElement>> =
        Rc::new(Class::new(HTMLVideoElement::new(...)));

    process_any_element(&*video_element);

    let node = video_element.first_child.clone();

    if let Some(element): Option<&DynClass<Element, ElementData>> = node.down_cast_ref() {
        // ...
    } else if let Some(text): Option<&DynClass<Element, TextNode>> = node.down_cast_ref() {
        // unreachable, because TextNode derives from ElementData ...
        // ...
    } else {
        // ...
    }
}

```

## Wrapping up

This RFC proposes an extremely lightweight way to add polymorphism. In terms of compiler integration. Only 2 intrinsic types (`TypeInfo` and `VTable`) and 2 intrinsic traits (`Coerce`, `CoerceRef`) are necessary, with all the functionality then being implemented in library code.

Furthermore, it supplements already existing Rust polymorphism without duplicating its functionality, therefore guaranteeing to the user that libraries using this functionality or not can still be hooked up together with little to no boilerplate.

Yet, despite being lightweight and rusty, it is quite possible to translate traditional objects hierarchy with a one-to-one mapping, use type aliases to mask the novelty and type inference to avoid ever mentioning it directly.

# Drawbacks

- **no sugar around `box`** : unfortunately, the story about `box` is unclear yet, so we can only provide a helper method, this makes creating/cloning smart pointers awkward.
- **heavier syntax** (`&T` vs `&Dyn<T>`): it is expected that the need for such bundling be rare, and it is possible to convert to `&T` immediately (so that only `struct` code and not `fn` code be affected).
- **opinionated** : not many building blocks here.

# Alternatives

## Comparison to existing RFCs

There are many other RFCs, as already mentioned:

- [#9](https://github.com/rust-lang/rfcs/pull/9): Fat Objects
- [#11](https://github.com/rust-lang/rfcs/pull/11): Extending Enums
- [#223](https://github.com/rust-lang/rfcs/pull/223): Trait Based Inheritance
- [#250](https://github.com/rust-lang/rfcs/pull/250): Associated Field Inheritance

This RFC emphasizes _flexibility_ and a clean separation of concern between payload (`struct`), behaviour (`trait`) and usage (`&T` or `&Dyn<T>`). The same `struct` or `trait` can freely be shared in situations where thin pointers are desirable or not.

This RFC can be seen as a refined version of Fat Objects (#9), proposing a more fully fleshed out implementation and simplifying the implementation of non-virtual methods by simply adding them to the `struct` rather than creating an extraneous `trait`. It could actually benefit from a better integration of custom DSTs in the language, as `DynClass` is not too well integrated.

Compared to `...` (#11), this RFC does not require distinguishing between `enum` that can be extended and `enum` that cannot (mixes payload and usage). This distinction already exists today in C++ (inheriting a class without a `virtual` destructor) and has proven to be a pain point of the language; it introduces a split in the language ecosystem between those `struct` that can be extended and those that cannot. On the contrary, this RFC emphasizes that every existing `trait` and `struct` can be reused, and no foresight is necessary when designing new ones. It is also significantly less ambitious, and does not attempt any large scale changes to the language beyond fulfilling the given requirements.

Compared to `Extend` (#223) or associated fields (#250), this RFC does not inject data in traits (mixes payload and behaviour). I consider this its main advantage. It neatly sidesteps the issue of splitting the ecosystem into stateful traits and stateless traits, and therefore guarantees that traits can be shared between any library, in any direction.

Compared to the associated fields (#250), this RFC's approach to fields is both cheaper than the indirect fields approach (with its required offset in v-table per field) and less constrained than the `#[repr(fixed)]` approach (which precludes implementing two fixed traits with contradicting requirements). It also does not require the compiler to try and guarantee the non-aliasing of fields. On the other hand, it is obviously less flexible given its conservative choice (no renaming/re-arrangement).

Compared to the associated fields (#250), this RFC's approach does not require that common fields be public, which is a violation of encapsulation. The `struct` can define methods with exclusive access to its fields, guaranteeing the invariants of its choice, and because those methods are not polymorphic they can be easily inlined. Still, if desired, its fields _can_ be public.

Compared to the Internal Vtable (#250), this RFC once again avoids enforcing that a `struct` or `trait` only be usable in a particular way (mixes payload and usage). This once again allows using either the `struct` or `trait` in other contexts, where this particular representation would be less attractive (it is known that LLVM has issues with devirtualizing calls through internal v-pointers, for example).

## Explicit Coercions

It is possible to require explicit coercions, however it seems strange in light of the `Deref` precedent and may lead to a usability hit because of the extra verbosity. Still, inference might make it sufficiently lightweight.

## No disambiguation in Data Polymorphism

It is possible to remove the necessity for disambiguation in parent's field or method selection by simply forbidding ambiguities, after all this can be checked easily enough.

Given that the necessity for disambiguation already arises when a single `struct` implements multiple `trait` with the same method name, it seems little effort to allow it.

On the other hand, the potential usability blow in forbidding ambiguities would be important. There is a reason it is allowed for `trait`s: requiring two 3rd party libraries not to impinge on each other names is reminiscent of the C days, where there were no namespace.

## Alternative Syntax for Data Polymorphism and disambiguation

Another syntax could be considered to provide data polymorphism, for example by using an attribute on a data-member (as #230).

Similarly, another syntax could be considered to provide disambiguation. C++ for example uses `child.Parent::method()`.

The current syntaxes, however, were selected by mirroring the syntax of trait polymorphism and trait disambiguation (respectively), increasing their accessibility and trying to avoid making the learning curve even steeper than it already is.

Still, as with naming, this is open to debate.

## Public/Private Data Polymorphism

As proposed, a `struct` may derive from another either publicly `struct A: pub B` or privately `struct A: B` with the latter being the default (as is usual in Rust: more capability is opt-in).

This RFC would be pretty much as useful without this distinction, in which case there are two alternatives:

- only public polymorphism: the diamond inheritance problem becomes bothersome, as the work-around today relies on privacy to enforce data coherence.
- only private polymorphism: in which case the user can publicize the relationship by implementing `Coerce` and `CoerceRef` manually; those traits are `unsafe` though.

I would lean toward the latter solution as it offers more encapsulation. It is in line with fields (private by default) and not with `trait`s (extended traits are public), and therefore since it adds fields it seems logical to follow their precedent.

## `Dyn` ?

The `Dyn` alias is optional. It is purely added for convenience.

## No common ancestor `()`

There does not seem to be any disadvantage in having `()` be a common ancestor to all `struct` given that it has not capability and no overhead.

Still, if it were rejected, the `Dyn` alias could still be implemented though as full-blown `struct` instead.

## `DynMultiClass` ?

In order to navigate through an inheritance tree, more information might be required than just a thin pointer, so as to be able to point _within_ the data.

It is possible to arrange the `VTable` structure such that navigating is easy, as demonstrated, by encoding a back pointer to the most derived type `TypeInfo` to the start of the `VTable` before each subtype's inlined list of methods. It might or might not be desirable, the cost being relatively minor as a single instance of a given `VTable` exists, and this instance is tightly packed in ROM.

This strategy, however, is probably less desirable for `struct`, since those are destined to be massively instantiated. In this case, a dedicated `struct DynMultiClass` could be added to `core::rtti`, which would maintain an third field (compared to `DynClass`): an offset in the `struct`.

This RFC seems complicated enough as it is, without inviting more trouble, so this is tabled for now.

> Note: the signature of `down_cast_struct` would become `fn (TypeId, isize) -> Option<isize>` for example.

## `Drop`

In this proposal, when `rtti` is enabled and a trait has multiple non-empty bases, the `drop` glue is duplicated at the start of the `VTable` of each non-empty base.

An alternative would be, in this case, to hoist it inside `TypeInfo`. Of course, it would then require two dereferences instead of one to access `drop`, which might cause performance penalties.

However, one more pointer in the `VTable` is not that costly (there are only so many of them), therefore this RFC promotes duplication, at least as the default case.

## `down_cast_trait`/`down_cast_struct` unification?

For clarity, two methods were provided.

Having two methods can be beneficial, as each is significantly simpler, however it can also lead to extra overhead (two indirect calls) when down-casting on both the `trait` and `struct` axes. A unified method could be implemented, either as replacement or in addition.

## Diamond inheritance handling

Diamond inheritance in `trait`s is already handled: the caller must disambiguate which super-trait she wishes to call.

Diamond inheritance in `struct`s is however much more complicated, there is a significant difference between having one field or two. A cursory search reveals that few languages have attempted to provide a method to share fields, most being content enough to be able to disambiguate.

Furthermore, a user-land solution to inconsistency exists: if parents are private (as the default), then it is up to the child `struct` to re-export their methods, and doing so it can easily enough ensure the consistency of both data. It is, of course, somewhat onerous and error-prone.

It seems that any language solution to this problem could be added backward compatibly.

This RFC seems complicated enough as it is, without inviting more trouble, so this is tabled for now.

# Unresolved questions

- `trait` `impl` cannot be private today, should we try to keep the Child/Parent relationship secret and if so how? Wiring privacy into `C: P` checks?
- How to guarantee that `VRef` only take a `trait` parameter? The answer is probably linked to how to get `VRef` to obtain its `&'static VTable` pointer.

# Change Log

## 2015-05-15

- Introduce `CoerceRefMut`: `&str` is coercible to `&[u8]` but making `&mut str` coercible to `&mut [u8]` may violate its soundness. Thus `CoerceRefMut` is now opt-in.
- Introduce `DownCastRefMut` for the same reason.
- Refactor `Coerce` and co to avoid associated types, as it seems that this prevents them from being implemented multiple times (with different targets) for the same time. In hindsight, it kind of feel obvious.
- Refactor `DownCast` and co for the same reasons.
- Remove any talk about tail-padding, as per cmr comment; it's left to an implementation detail.
- Remove any talk about `cfg` attributes, it's distracting.
- Expand Static Dispatch section
- `DynClass` cannot implement multiple `Deref`, so move to explicit methods

---

<div class="post-metadata">

**Author:** ![Jexell](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jexell/32/3105_2.png) [@Jexell](https://internals.rust-lang.org/u/Jexell)\
**Post date:** [May 14, 2015, 9:20pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/2 "2015-05-14T21:20:36Z")

</div>

The proposal looks really nice. There are two things I don’t understand, although this may be due to me having a lack of understanding of rust in general. The proposal proposes to add a `cfg` attribute to control the emission of `vtable`s–why can you not have thin pointers which can be cast to fat pointers? My other question is that `rtti` appears to duplicate `Any`–would it be possible to adapt `Any` and have greater control over whether or not run-time type information is included?

---

<div class="post-metadata">

**Author:** ![cmr](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cmr/32/5_2.png) [@cmr](https://internals.rust-lang.org/u/cmr)\
**Post date:** [May 14, 2015, 11:03pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/3 "2015-05-14T23:03:49Z")

</div>

> [@matthieum](#):
>
> Note: the compiler should automatically implement the Coerce and CoerceRef traits, when it makes sense, between Parent and Child. This trait should be pub only if Parent is pub.

Trait impls cannot be private. You either have the impl, or you don't.

> [@matthieum](#):
>
> This RFC defines that () (the unit type) is a common ancestor to all struct:

What is the motivation for this?

> [@matthieum](#):
>
> The memory layout of a given struct may imply padding because of the alignment requirements of the various data members. Rust makes no guarantee on the memory layout (contrary to C which guarantees the order in which the fields appear), so this RFC will concentrates on tail-padding.

This isn't strictly true, because of the `repr` attribute.

> [@matthieum](#):
>
> This RFC proposes that Bar be allowed to stash its c data member in the tail-padding of Foo, so as to allow a well packed representation.

This is probably fine, but needs the additional restriction that the offset from the base of the parent is of a suitable alignment for the whole struct, and that it (minus any of its "tail padding") fits in the tail padding of the parent. Unless you're proposing individual fields get packed in the padding, instead of the whole thing, and that it gets extended as necessary? I think this section should be removed from the RFC. It's an implementation detail. I foresee complications arising when `&mut` gets involved (for example, `*a = b` might blast the padding. We don't define what happens to the padding, which is sometimes beneficial as it enables simpler codegen at times).

> [@matthieum](#):
>
> It becomes (?) possible to guarantee static dispatch of a trait method, by explicitly selecting the enum or struct for which it was implemented:

Is it not always possible? Today, if you don't have a trait object, you always get static dispatch. This section isn't very clear to me, I'm not sure what it's trying to point out. I have no idea what `Child` is or its relation to any other structs or traits.

> [@matthieum](#):
>
> impl\<Trait\> VRef\<Trait\> {

There's no way to ensure that the type parameter is only substituted with a trait.

> [@matthieum](#):
>
> \_: [u8], // Attempt to prevent `DynClass` from being accidentally used by value

Does `DynClass` actually need to be unsized? Isn't it enough that it not be `Copy`? (Since it's only ever behind a `&` (unless it can be behind a `&mut`? You never mention `&mut` here), you cannot move out of the `&`).

* * *

Ok, so finishing the RFC I see you address some of this in the "Alternatives". But, you claim that these polymorphism traits can be implemented in a library. I agree! Considering how complex this system is, I would like to see an out-of-tree implementation of just the library bits that uses hand-rolled vtables as necessary. Compiler magic is _not_ necessary to validate the idea.

I'm very uncomfortable with this proposal. Something about it sits wrong with me. That's about all the concrete feedback I have now, though.

---

<div class="post-metadata">

**Author:** ![bjadamson](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bjadamson/32/52_2.png) [@bjadamson](https://internals.rust-lang.org/u/bjadamson)\
**Post date:** [May 15, 2015, 6:58am UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/5 "2015-05-15T06:58:20Z")

</div>

One aspect of this I really like is how you sperated data and trait polymorphism. On mobile I will try and add to this when I get access to a computer.

---

<div class="post-metadata">

**Author:** ![pythonesque](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pythonesque/32/336_2.png) [@pythonesque](https://internals.rust-lang.org/u/pythonesque)\
**Post date:** [May 15, 2015, 2:58pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/6 "2015-05-15T14:58:42Z")

</div>

What sits wrong with you specifically? It actually doesn’t seem like a terribly complex proposal to me–that a lot of the stuff it’s describing can be done in-language strikes me as only a good thing.

My main concern was that despite the length and the in-depth nature of the description, I still felt pretty uncertain about some of the technical details. I don’t think this is due to complexity, but rather that a lot of the stuff just doesn’t seem necessary (to me, anyway).

For starters, I absolutely love the idea of `Transmutable`, `Coercible` and `Conertible`. I think these will be very important towards making a broad range of patterns safe, inheritance being only one of them. If the compiler can work these out automatically, or they can inform layout, so much the better.

I do not think `Coerce` is a good idea. There’s a reason we don’t have `DerefMove` yet. In particular, making `Coerce` happen _automatically_ sounds like a recipe for a lot of either bugs or surprising behavior, since it can chop off part of a structure!

I like the idea of inheritance being sugar for deriving a ton of traits. In fact, I would much rather do it as a `deriving` / glorified macro (perhaps a `deriving` with arguments–this is something I’ve actually wanted for a while, though I don’t know if it’s feasible in the grammar) rather than as a more heavyweight language feature. Because this only affects data layout, concerns about how it works with generic / trait subtyping don’t apply.

A fair amount of the padding section seems not too interesting to me, though I can’t speak for others. I think people would probably be okay with requiring `repr(C)` if you’re relying on shared layout between two structs (it’s currently required for transmute to be well-defined).

I’m much more interested in how all of this stuff applies to `enum`s–does it? If not, it seems like a wasted opportunity, since one case that I _frequently_ want is to be able to turn a set of `enum`s into a larger or smaller set of `enum`s that share the same base (as long as I’ve verified beforehand that all the necessary variants are shared between them).

I’m also interested in how generics fit in with all this. They aren’t really discussed, so I’m not sure if they present any additional challenges when it comes to dealing with alignment and so on.

I am not really sure about the part where you have to specify which implementations from the parent you are using. What does that buy you, exactly? What if it’s a new trait that’s defined in your own crate; do you have to define it for both the parent and any children you’re using it for there, too?

In general I’m not a fan of structural inheritance also implying implementation inheritance–the structural sharing feels like it should be able to stand on its own, and the trait inheritance for structures could just as easily be replaced with macros in the rare cases where it’s actually desired.

All the `cfg` stuff sounds pretty bad to me. Why do we need it for every trait? We already have a `Reflect` OIBIT, which seems like a perfect candidate for deciding whether or not to expose RTTI information, and trait objects, which expose vtable information; neither option splits the language based on whether you want to generate vtables or not.

I flat out don’t understand why you need this new and elaborate `rtti` model for downcasts. Maybe there’s something I’m missing, but what is wrong with just using the type ID that we already have (which, again, is already bounded by `Reflect`)? This is how `Any` does it and it seems to work fine. Also, I don’t know Servo’s precise requirements, but downcasting to an intermediate trait may be what they’re interested in, since Rust can already downcast just fine to an intermediate type (well… I’m not actually exactly sure why they need cheap downcasting at all, so I probably shouldn’t presume that).

Thin pointers are probably the most important thing Servo needs, and also probably the most useful thing I expect to come out of all these discussions, so it’s a bit weird that they receive so little attention here.

`()` as a common ancestor really makes no sense to me. What about, say, `[T ; 0]`, or `PhantomData`? I think the proposal would be better without this.

---

<div class="post-metadata">

**Author:** ![Jexell](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jexell/32/3105_2.png) [@Jexell](https://internals.rust-lang.org/u/Jexell)\
**Post date:** [May 15, 2015, 3:37pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/7 "2015-05-15T15:37:18Z")

</div>

> [@pythonesque](#):
>
> For starters, I absolutely love the idea of Transmutable, Coercible and Conertible. ... I do not think Coerce is a good idea.

I don't quite get what you mean. From my understanding the proposal seems to suggest adding `Coerce` to add the concept of something being `Transmutable`, `Coercible` and `Convertible`.

---

<div class="post-metadata">

**Author:** ![matthieum](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matthieum/32/4023_2.png) [@matthieum](https://internals.rust-lang.org/u/matthieum)\
**Post date:** [May 15, 2015, 5:33pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/8 "2015-05-15T17:33:04Z")

</div>

So, to answer your questions:

- `vtable`: the thin pointers can be cast to fat pointers (the reverse is not necessarily true), actually, using a single brand of `vtable` is the goal and this attribute just controls whether one wishes for dynamic polymorphism or not; as discussed in the alternatives it could be left out easily.

- `rtti`: I believe `Any` could be optimized to take advantage of the newly emitted RTTI information to navigate the type hierarchy. As far as I know today you can only get the “most-derived-type” out of `Any` whereas with RTTI information you could down-cast to any type in the hierarchy.

---

<div class="post-metadata">

**Author:** ![matthieum](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matthieum/32/4023_2.png) [@matthieum](https://internals.rust-lang.org/u/matthieum)\
**Post date:** [May 15, 2015, 6:37pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/9 "2015-05-15T18:37:59Z")

</div>

> My main concern was that despite the length and the in-depth nature of the description, I still felt pretty uncertain about some of the technical details. I don't think this is due to complexity, but rather that a lot of the stuff just doesn't seem necessary (to me, anyway).

I'll put up a revision which purges out all talk about tail-padding and `cfg` configurability.

> I do not think Coerce is a good idea. There's a reason we don't have DerefMove yet. In particular, making Coerce happen automatically sounds like a recipe for a lot of either bugs or surprising behavior, since it can chop off part of a structure!

Actually, `std::mem::transmute` refuses to transmute between data of difference sizes. I would also note the `trait` is `unsafe` precisely because you are toying with complications here.

> A fair amount of the padding section seems not too interesting to me, though I can't speak for others. I think people would probably be okay with requiring `repr(C)` if you're relying on shared layout between two structs (it's currently required for transmute to be well-defined).

I totally scrapped it out, it was distracting.

> I'm much more interested in how all of this stuff applies to enums--does it? If not, it seems like a wasted opportunity, since one case that I frequently want is to be able to turn a set of enums into a larger or smaller set of enums that share the same base (as long as I've verified beforehand that all the necessary variants are shared between them).

No, not one bit.

It is easy for `struct` to share fields, but for `enum` to share variants brings complications:

- if you extend the `enum` (add more variants), then matches on the parent `enum` do not cover the extra variants
- if you refine the `enum` (remove some variants), then by seeing a mutable reference to the parent, you can add those variants

As a result, it seems that with `enum` the number of variants must be fixed. I cannot see how to deal with that.

> I'm also interested in how generics fit in with all this. They aren't really discussed, so I'm not sure if they present any additional challenges when it comes to dealing with alignment and so on.

I do not think so; they were not discussed because I did not see any additional challenges. I may just be short-sighted, of course.

> I am not really sure about the part where you have to specify which implementations from the parent you are using. What does that buy you, exactly? What if it's a new trait that's defined in your own crate; do you have to define it for both the parent and any children you're using it for there, too?

Rust tries to shy away as much as possible from implicit assumptions; I was just trying to play it safe.

> All the cfg stuff sounds pretty bad to me. Why do we need it for every trait? We already have a Reflect OIBIT, which seems like a perfect candidate for deciding whether or not to expose RTTI information, and trait objects, which expose vtable information; neither option splits the language based on whether you want to generate vtables or not.

> I flat out don't understand why you need this new and elaborate rtti model for downcasts. Maybe there's something I'm missing, but what is wrong with just using the type ID that we already have (which, again, is already bounded by Reflect)? This is how Any does it and it seems to work fine. Also, I don't know Servo's precise requirements, but downcasting to an intermediate trait may be what they're interested in, since Rust can already downcast just fine to an intermediate type (well... I'm not actually exactly sure why they need cheap downcasting at all, so I probably shouldn't presume that).

I must admit having some difficulties in using `Any`, so it may well be that it can accomplish much more than I credit it for.

As far as I could see in my exploration, though, `Any` seemed to suffer from two issues:

- it could only be build from a concrete type
- it could only down-cast to that same concrete type

I've tried to coax it to down-cast to traits, but was left quite frustrated by the experience (`downcast_mut` only targets `Sized` types, for example).

> Thin pointers are probably the most important thing Servo needs, and also probably the most useful thing I expect to come out of all these discussions, so it's a bit weird that they receive so little attention here.

Yes, all of that to enable thin pointers... `Box<DynClass<_, _>>` is a thin pointer, and so is `Box<Dyn<_>>`.

> `()` as a common ancestor really makes no sense to me. What about, say, [T ; 0], or PhantomData? I think the proposal would be better without this.

Actually, it seems the de-facto common ancestor already; I trudge through a few standard libraries which use an unknown type (in unsafe code) and it seems to always end up being either `*const ()` or `*mut ()`.

I thought about leaving it out, however I really wanted to present `Dyn<T>` as a thin pointer alternative to `&T` and the cheapest option was for it to be an alias of `DynClass<T, ()>`. An earlier version of the RFC had a whole new lot type, with conversions back and forth, it felt quite complicated for not that much.

---

<div class="post-metadata">

**Author:** ![matthieum](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matthieum/32/4023_2.png) [@matthieum](https://internals.rust-lang.org/u/matthieum)\
**Post date:** [May 15, 2015, 7:18pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/10 "2015-05-15T19:18:01Z")

</div>

Thanks a lot for the detailed answer.

> Trait impls cannot be private. You either have the impl, or you don't.

This begs the question of whether advertising the relationship between child and parent is mandatory / not important / harmful.

Another solution would be to pin the condition for checking whether two `struct` are in a relationship hinge on `Child: Parent` syntax (like for traits) and align this check on the privacy setting selected.

Do you think it would work better?

> What is the motivation for [defining () as common ancestor]?

It is a de-facto ancestor today in the standard libraries, it seems, as `*const ()` and `*mut ()` are used a lot.

I was hoping to build on this to allow a slick definition of `Dyn<T>`.

I would find it unfortunate for multiple developers to come up with incompatible empty structs just to have a "data-less" thin pointers as they would not be compatible with each others.

> I think this section should be removed from the RFC. It's an implementation detail.

Agreed, I am culling it. The RFC is big enough as it is, and such guarantees are easier to add than remove.

> Is [static dispatch] not always possible?

I need to rework this section.

> There's no way to ensure that the type parameter is only substituted with a trait.

Quite annoying; indeed. There is also a big "blank" here in how the `VRef` instance is supposed to get a hold of the `&'static VTable` corresponding to its `Trait` parameter...

The parameter today is mostly used in `where` clause; to ensure that two traits can share the same v-pointer.

I need to sleep on this.

> Does `DynClass` actually need to be unsized?

My apologies here, `DynClass` can indeed be used behind `&mut` much like a `trait` can; it would otherwise be too restrictive. On top of that, being able to return a `DynClass` by value would lead to slicing.

`DynClass` should never be stack-allocated; nor should it be passed (or returned) by value. It's a view into a bigger object.

And I currently see no way how to ensure those restrictions are followed (short of the `_: [u8]` trick, which will fall short whenever the compiler is upgraded to be able to return DST).

> That's about all the concrete feedback I have now, though.

It was helpful, thank you for your time.

> I'm very uncomfortable with this proposal. Something about it sits wrong with me.

This sounds ominous. Without imposing, I would really like if you could find out what is causing this bad intuition.

> But, you claim that these polymorphism traits can be implemented in a library.

Yes, good idea. It will also help me sort out the bugs that slipped through the crack; I've got some time on my hands in the coming week, so I'll try to hack it.

---

<div class="post-metadata">

**Author:** ![cmr](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cmr/32/5_2.png) [@cmr](https://internals.rust-lang.org/u/cmr)\
**Post date:** [May 15, 2015, 10:57pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/11 "2015-05-15T22:57:39Z")

</div>

> [@matthieum](#):
>
> Explicit Coercions
> 
> It is possible to require explicit coercions, however it seems strange in light of the Deref precedent and may lead to a usability hit because of the extra verbosity. Still, inference might make it sufficiently lightweight.

So you would like `Coerce` to be applied whenever applicable and necessary? I'm not sure if the rewrite system implied by this _and_ `Deref` (and `Convertible`?) is terminating or confluent. I'd need to sit down and think about it some more. No longer using an associated type worries me. A precise algorithm would be _really_ appreciated!

---

<div class="post-metadata">

**Author:** ![matthieum](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matthieum/32/4023_2.png) [@matthieum](https://internals.rust-lang.org/u/matthieum)\
**Post date:** [May 16, 2015, 11:06am UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/12 "2015-05-16T11:06:20Z")

</div>

I would note that there is neither a `Convertible` nor a a `Transmutable` trait, only the `Coerce`/`CoerceRef`/`CoerceRefMut` family.

I am not too satisfied with the move away from associated types either, as it means that the author of the `struct` loses control. With associated types only the crate containing the `struct` could implement the various `Coerce`, which makes it more resilient to changes (even though it’s labelled unsafe).

On the other hand, an associated type in `Coerce` and co restricts to single “inheritance” line. Today, as defined here, you can only safely coerce into:

- an empty type
- the first non-empty type

Maybe the lack of multiple targets would not be too much of an issue if we instead let the user pick to which type he wishes for automatic coercion; however it would only be safe if the compiler could check that the coercion is valid, so the trait would need some compiler “hook”, and I am wary of making the use of `unsafe` common-place.

That being said, the problem here might be that I use `Coerce` for two roles:

- the ability to auto `Deref`
- as a constraint on functions

I have to see what I could do if `Coerce` was used simply as constraint, and the user had to implement `Deref` for smooth conversions. It would remove the dual mechanism and the various ambiguities or surprising behaviours that could arise from it.

_Note: this seems like an instance where associated constants (and the ability to check them in `where` clauses) would really help; with a `trait Derived<T> where Self: T { isize const offset; }`, we would not need `Coerce` for constraints check._

---

<div class="post-metadata">

**Author:** ![Jexell](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jexell/32/3105_2.png) [@Jexell](https://internals.rust-lang.org/u/Jexell)\
**Post date:** [May 16, 2015, 1:22pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/13 "2015-05-16T13:22:12Z")

</div>

One potiential reason to perhaps not use `()` is that it creates two ways of extending every single type:

```rust
impl TraitName for T {...}

```

and

```rust
impl TraitName for () {...}

```

---

<div class="post-metadata">

**Author:** ![matthieum](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matthieum/32/4023_2.png) [@matthieum](https://internals.rust-lang.org/u/matthieum)\
**Post date:** [May 16, 2015, 3:52pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/14 "2015-05-16T15:52:33Z")

</div>

Interesting, however the two are not actually equivalent.

While a `Child` can easily “re-export” its `Parent` traits, it has to do so explicitly `impl TraitName for Child {}` in the current proposal. Therefore:

- traits implemented for any `T` (no bound) are implicitly implemented for any type
- traits implemented for `()` have to be implicitly re-implemented for any type, though that type might delegate the implementation by not overriding any method

It does produce a conflict though: now you can provide default method implementations either by doing so in the trait or by doing so for `()`.

It is unclear whether this is an issue.

---

<div class="post-metadata">

**Author:** ![glaebhoerl](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/glaebhoerl/32/1978_2.png) [@glaebhoerl](https://internals.rust-lang.org/u/glaebhoerl)\
**Post date:** [May 16, 2015, 7:57pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/15 "2015-05-16T19:57:02Z")

</div>

I would need to spend some more time and effort to really understand most of this. (_If_ you feel like helping me (there’s no obligation!), one thing that I suspect might be very helpful is if the RFC were organized more along the lines of “1. this is what we want to be able to do (e.g. such-and-such downcasting) 2. this is why we want to be able to do it (e.g. something something DOM) 3. this is how we propose to make it possible (e.g. `rtti` stuff)” (or maybe with 1 and 2 swapped) - _for each_ feature. Right now it feels like a quick recap of requirements at the beginning and end, and a big grab-bag of features in the middle, with the connections and motivations not being immediately obvious. I suppose all these might be more apparent to someone who’s been following the various “inheritance-ish” RFCs in depth, but I regrettably haven’t.)

A couple of quick comments I can make though -

It’s my fault for introducing this confusion originally (in the [proposal](https://github.com/rust-lang/rust/issues/9912#issuecomment-36073562) I made in haste) and the damage is probably irreparable, but I really think `Coerce`/“Coercible” is the wrong terminology here in the Rustic context. It’s an unfortunate case that the Haskell and Rust communities use the same words to mean different things, and I naively imported not just the concept but also its name from how GHC has it. But to recap, for the concept of reinterpreting the raw bytes of one type as another type, Haskell uses the word “coerce” (`Coercible`, `Coercion`, `coerce`, and `unsafeCoerce`) - and for the same thing, Rust uses the word “transmute” (our `mem::transmute` is the same thing as their `unsafeCoerce`). Meanwhile, Rust already uses the word “coerce”/“coercion” to mean a _different_ thing: automatic compiler-inserted conversions between types (which are _not_ in general reinterpretations of raw bytes - e.g. what we call “deref coercions”, which invoke `Deref::deref` rather than `mem::transmute`).

Basically, I would prefer to use something like “safely transmutable” where you currently have “coercible”.

And with respect to the formulation of the traits, I believe it is your intent that the implementation (as currently named) of `coerce`{,`_ref`{,`_mut`}} is always the same - it’s always `mem::transmute`. In other words, implementors of these traits _should not_ be able to override these methods with different implementations. If that’s the case, the right thing to do would be to take the method out of the trait (the trait is now method-less) and provide it as a free-standing function instead (which requires the given trait as a bound).

---

<div class="post-metadata">

**Author:** ![gereeter](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gereeter/32/3175_2.png) [@gereeter](https://internals.rust-lang.org/u/gereeter)\
**Post date:** [May 19, 2015, 2:28pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/16 "2015-05-19T14:28:05Z")

</div>

Note: I'm the author of [Trait Based Inheritance](https://github.com/rust-lang/rfcs/pull/223).

> [@matthieum](#):
>
> A type U is said to be coercible to a type T when transmuting U to T "works". This is voluntarily vague, and sufficient for this RFC.

I think that it isn't sufficient to leave this vague in a final, on-the-repo RFC, but it sounds like this is exactly the same relation that @glaebhoerl and I put forward as in [RFC 91](https://github.com/rust-lang/rfcs/pull/91), which does give a more formal description. Note that RFC 91 uses the term `Coercible` for your `Coerce`, both of which, as @glaebhoerl have pointed out, are probably suboptimal.

> [@matthieum](#):
>
> unsafe trait Coerce\<Target\> { fn coerce(self) -\> Target { mem::transmute(self) } }
> 
> unsafe trait CoerceRef\<Target\> { fn coerce\_ref(&self) -\> &Target { mem::transmute(&self) } }
> 
> trait CoerceRefMut\<Target\>: CoerceRef\<Target\> { fn coerce\_ref\_mut(&mut self) -\> &mut Target { mem::transmute(&mut self) } }

I have a couple questions here.

1. What is the motivation for having separate `CoerceRef` and `CoerceRefMut` traits instead of just `Coerce` `impl`s for references (e.g. `impl<'a> Coerce<&'a Target> for &'a Source`)?

2. As @glaebhoerl pointed out, I'm not sure that these traits should actually have methods. Since every implementation should be `mem::transmute`, `Coerce` and friends can just be marker traits, and there can be a free-standing function

3. Unless the `impls` of these traits are very carefully generated by the compiler, these traits will result in wildly incoherent implementations. This actually isn't a problem for marker traits, and I've been thinking of writing up an RFC to relax the coherence requirements for empty traits, but it would result in ambiguities in generated code if the traits had methods. Whatever strategy you choose to take for this, I think the coherence issue should be mentioned.

4. I'm not sure that it is safe for `CoerceRefMut` to be a safe trait. Taking the `&mut str` to `&mut [u8]` issue, leaving `CoerceRefMut` safe would allow an incorrect implementation. Coherence checks might prevent this at the moment, but it isn't totally clear and, as mentioned in the previous point, the coherence rules might have to be weakened for these traits.

> [@matthieum](#):
>
> struct StructName: [pub] StructName (+ [pub] StructName)\* { // other attributes }

This looks nice, but one lighterweight alternative would be a `#[parent]` attribute that you could apply to the fields of a struct. This would make access of parents more explicit and would allow automatic conversions to be easily chosen or rejected through a choice of a `Deref` implementation.

> [@matthieum](#):
>
> By deriving from another struct, the derived struct embeds its parents' fields. However, due to encapsulation, it can only access fields that it could access if the parent was an attribute.

Continuing from the previous `#[parent]` suggestion, this would fall immediately out of using fields for data inheritance.

> [@matthieum](#):
>
> By default, should a parent of a struct implement a trait, it is not necessary for the struct to implement any method, though it still has to explicitly declare the trait implementation:

This feels _very_ nice, though I'm not completely clear on what would happen if multiple parents implemented the trait.

> [@matthieum](#):
>
> It would be better if the compiler could perform the up-casts implicitly, much like with Deref, there seems to be little point in having the user fiddling with as over and over.

I'd rather have `DynClass` actually implement `Deref<Target=S>` and have the structs `Deref` to their parents, keeping only one system of implicit conversions.

> [@matthieum](#):
>
> fn make\_dynamic\<T, S\>(original: Box\<Class\<T, S\>\>) -\> Box\<DynClass\<T, S\>\> { unsafe { mem::transmute(original) } }

Why not just have

```rust
unsafe impl<T, S> Coerce<Box<DynClass<T, S>>> for Box<Class<T, S>> { }

```

?

> [@matthieum](#):
>
> fn up\_cast\<T, S, B, P\>(original: Box\<DynClass\<T, S\>\>) -\> Box\<DynClass\<B, P\>\> where T: B, S: P, S: CoerceRef\<P\>;

Similarly, this could be done via `Coerce`.

> [@matthieum](#):
>
> opinionated: not many building blocks here.

I know this is just my strong opinion aligning with yours, but I view this as an advantage.

> [@matthieum](#):
>
> Compared to Extend (#223) or associated fields (#250), this RFC does not inject data in traits (mixes payload and behaviour).

`Extend` explicity did _not_ injecct data into traits. Rather, `Extend` corresponds almost exactly with your `CoerceRef` trait - it simply stated a claim that the data was there, allowing you to safely coerce references, doing an upcast. In fact, I find our proposals largely aligned with each other, though I think you definitely have a better, cleaner downcasting story than I did.

My general feeling is that I definitely like this proposal, probably in large part because of its similarity to the proposal I made. I think that focusing on having a set of features that do not step on each others' toes and work very well together is incredibly important, and I think you have done a good job at doing that.

---

<div class="post-metadata">

**Author:** ![Jexell](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jexell/32/3105_2.png) [@Jexell](https://internals.rust-lang.org/u/Jexell)\
**Post date:** [May 19, 2015, 5:34pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/17 "2015-05-19T17:34:19Z")

</div>

@matthieum why do need to have both `Class` and `DynClass` and in addition to that `TypeInfo`, `VTable` and `VRef`? Could you not just have:

```rust
struct DynClass {
    pub data: *mut (),
    pub vtable: *mut (),
}

```

Due to differences between Rust and a lot of other OO languages maybe it would be better if something like `DynStruct` or `StructObject` (like `TraitObject`) was used instead of `DynClass` / `Class`.

Continuing on from the discussion on `()`, if `T` safely transmutes to `T` then it would not inherit from `()`.

---

<div class="post-metadata">

**Author:** ![jan\_hudec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jan_hudec/32/4100_2.png) [@jan\_hudec](https://internals.rust-lang.org/u/jan_hudec)\
**Post date:** [May 19, 2015, 8:29pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/18 "2015-05-19T20:29:54Z")

</div>

> [@matthieum](#):
>
> - thin pointers

Why are thin pointers so important? It seems to be a lot of work to get them.

Also the other features don't seem to depend on that (and they shouldn't; thin pointers may be useful somewhere, but I still think most code will prefer to stick with trait references), so perhaps the Class/DynClass stuff could be split off to separate RFC to further simplify the discussion.

---

<div class="post-metadata">

**Author:** ![matthieum](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matthieum/32/4023_2.png) [@matthieum](https://internals.rust-lang.org/u/matthieum)\
**Post date:** [May 20, 2015, 4:31pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/19 "2015-05-20T16:31:02Z")

</div>

I did not make the list of requirements, they came from Servo.

If I remember correctly the problem in Servo is that there is a _lot_ of pointers and therefore going down from 16 bytes to 8 bytes provides a substantial memory gain.

As for splitting Class/DynClass into another RFC; well, those two classes are the RFC, everything before is just erecting the necessary scaffolding to get there, so I would be quite reluctant at the early stage. I believe it’s important, in this discussion, to keep the whole picture in mind; afterward, when the time comes to implement stuff and the roadmap is clear then working in smaller increments (or switching out some of the scaffolding for other bits) will be much easier.

---

<div class="post-metadata">

**Author:** ![jan\_hudec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jan_hudec/32/4100_2.png) [@jan\_hudec](https://internals.rust-lang.org/u/jan_hudec)\
**Post date:** [May 21, 2015, 4:01pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/20 "2015-05-21T16:01:28Z")

</div>

> [@matthieum](#):
>
> If I remember correctly the problem in Servo is that there is a lot of pointers and therefore going down from 16 bytes to 8 bytes provides a substantial memory gain.

And I suspect there will be many projects that will want inheritance. but will _not_ get big gain from this. The 8 bytes go to the Class/DynClass, so if there are many objects, but few pointers to each, the gain won't be that big.

On the other hand, servo would surely get this benefit already _without_ any of the inheritance stuff. Trait objects are there and they use them already and this is simply optimization for trait objects.

That's why I think this is two mostly independent things that should be proposed separately. One is inheritance, the other is optimizing trait references.

---

<div class="post-metadata">

**Author:** ![aturon](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aturon/32/3272_2.png) [@aturon](https://internals.rust-lang.org/u/aturon)\
**Post date:** [May 21, 2015, 11:00pm UTC](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029/21 "2015-05-21T23:00:40Z")

</div>

@matthieum

Just wanted to drop a quick note, first of all to thank you for your effort here, and also to let you know that @nikomatsakis and I are both slowly making our way through. It’s been a crazy week post-1.0, but I hope to leave some thoughts next week.

[Next page](https://internals.rust-lang.org/t/pre-rfc-disjoint-polymorphism/2029.md?page=2)
