I can't figure out how GitHub works, so can someone please commit the following 
RFC, thank you:

- Start Date: 2014-04-17
- RFC PR #:
- Rust Issue #:

# Summary

Add the ability to specify that a type, which implements a certain trait, must 
have certain set of fields (data members) of certain types so that the trait 
may then use those expected fields in the methods it provides (has a default 
definition for).

# Motivation

This enables much more code re-use than traits currently do. This also provides 
what other languages call "multiple inheritance" without facing the so called 
"diamond problem".

# Detailed design

A trait may specify a set of expected fields. For each expected field the trait 
definition must provide a type and a unique name. When a type implements such a 
trait, it must specify which of its fields correspond with each of the trait's 
expected fields. The types of the fields must match with the types of the 
corresponding expected fields of the trait and no two fields of the type may 
map to the same expected field of the trait. The type implementing the trait 
may have more fields than there are expected fields in the trait, and the order 
of fields doesn't matter. The knowledge of which field each expected field 
corresponds to can then be used by the trait to locate and use the data it 
expects to find by adding the offset of the field to a pointer to the first 
byte of ```self``` and by re-interpreting the pointed-to data as the expected 
field's type.

What follows next is an example code snippet where I present the syntax I 
propose for this feature. And after that I'll provide the (currently valid) 
Rust code which the first example would conceptually correspond with.

Example 1: The proposed syntax
```
trait Unify<T: Clone> {
    Self {
        x: T,
        y: T
    }

    fn unify(&mut self) {
        self.y = self.x.clone();
    }
}

struct Stuff {
    a: u32,
    b: u32
}

impl Unify<u32> for Stuff {
    Stuff {
        x => a,
        y => b
    }
}
```

Example 2: The code that corresponds with example 1
```
use std::cast::transmute;

trait Unify<T: Clone> {
    fn x_offset(&self) -> int; // This should be replaced with an associated 
constant once we get those
    fn y_offset(&self) -> int; // This should be replaced with an associated 
constant once we get those

    fn unify(&mut self) {
        unsafe {
            let self_x: *mut T = transmute::<*mut u8, *mut T>(transmute::<&mut 
Self, *mut u8>(self).offset(self.x_offset()));
            let self_y: *mut T = transmute::<*mut u8, *mut T>(transmute::<&mut 
Self, *mut u8>(self).offset(self.y_offset()));

            *self_y = (*self_x).clone();
        }
    }
}

struct Stuff {
    a: u32, // is at offset 0 bytes
    b: u32 // is at offset 4 bytes
}

impl Unify<u32> for Stuff {
    fn x_offset(&self) -> int {
        0 // The offset of field 'a'
    }

    fn y_offset(&self) -> int {
        4 // The offset of field 'b'
    }
}
```

# Alternatives

Code re-use is possible also with macros, but this solution is much more 
elegant and may allow better opportunities for the compiler to reduce template 
code-bloat.

# Unresolved questions

The syntax is completely open to debate.

_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to