New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow fields in traits that map to lvalues in impl'ing type #1546

Closed
wants to merge 5 commits into
base: master
from

Conversation

Projects
@nikomatsakis
Contributor

nikomatsakis commented Mar 16, 2016

UPDATE: The finishing touches and final conversation on this RFC are taking place in a dedicated repository, as described in this comment.


The primary change proposed here is to allow fields within traits and then permit access to those fields within generic functions and from trait objects:

  • trait Trait { field: usize }
  • Implementing type can "direct" this field to any lvalue within itself
  • All fields within a trait or its supertraits must be mapped to
    disjoint locations

Fields serve as a better alternative to accessor functions in traits. They are more compatible with Rust's safety checks than accessors, but also more efficient when using trait objects.

Many of the ideas here were originally proposed in rust-lang/rfcs#250 in some form. As such, they represent an important "piece of the puzzle" towards solving rust-lang/rfcs#349.

cc @eddyb @aturon @rust-lang/lang

Rendered view.

Planned edits

  • Adopt let syntax for declaring fields in traits and impls. (decided against this)
  • Clarify that there are "private type in public API" rules that apply to the type of a field.
  • Decide whether mut is required for mutable access. (At minimum, add as an unresolved question.)
  • Typo

@nikomatsakis nikomatsakis added the T-lang label Mar 16, 2016

@nikomatsakis nikomatsakis self-assigned this Mar 16, 2016

@oli-obk

This comment has been minimized.

Show comment
Hide comment
@oli-obk

oli-obk Mar 16, 2016

Contributor

#1215 also addresses the borrowck problem with accessors, but still has the poor performance issue and there wasn't any talk about traits (yet). The suggestion was some kind of explicit disjoint partitions (e.g. struct field names) that can be mentioned in references to allow partial borrows.

Contributor

oli-obk commented Mar 16, 2016

#1215 also addresses the borrowck problem with accessors, but still has the poor performance issue and there wasn't any talk about traits (yet). The suggestion was some kind of explicit disjoint partitions (e.g. struct field names) that can be mentioned in references to allow partial borrows.

Show outdated Hide outdated text/0000-fields-in-traits.md
```rust
trait Trait {
field1: Type1, // <-- fields within a block separated by commas.

This comment has been minimized.

@ticki

ticki Mar 16, 2016

Contributor

Another possibility is to declare "fields" (accessors) using a syntax similar to variable declaration:

trait Trait {
    let field1: Type1;
    let field2: Type2;

    fn foo();
}

This also signifies that it isn't really a field, but more an associated value. It also looks nicer in impls.

@ticki

ticki Mar 16, 2016

Contributor

Another possibility is to declare "fields" (accessors) using a syntax similar to variable declaration:

trait Trait {
    let field1: Type1;
    let field2: Type2;

    fn foo();
}

This also signifies that it isn't really a field, but more an associated value. It also looks nicer in impls.

This comment has been minimized.

@oli-obk

oli-obk Mar 16, 2016

Contributor

this syntax is mentioned 10 lines below.

@oli-obk

oli-obk Mar 16, 2016

Contributor

this syntax is mentioned 10 lines below.

This comment has been minimized.

@ticki

ticki Mar 16, 2016

Contributor

Oh, well. I missed that.

@ticki

ticki Mar 16, 2016

Contributor

Oh, well. I missed that.

This comment has been minimized.

@nikomatsakis

nikomatsakis Mar 16, 2016

Contributor

Another possibility is to declare "fields" (accessors) using a syntax similar to variable declaration:

trait Trait {
    let field1: Type1;
    let field2: Type2;

    fn foo();
}

This also signifies that it isn't really a field, but more an associated value.

Yeah, I don't hate this. It might be better, all things considered. I
like having all trait items start with a keyword, probably helps us
with future expansions of the syntax, and avoids the awkward , vs
; quesiton.

@nikomatsakis

nikomatsakis Mar 16, 2016

Contributor

Another possibility is to declare "fields" (accessors) using a syntax similar to variable declaration:

trait Trait {
    let field1: Type1;
    let field2: Type2;

    fn foo();
}

This also signifies that it isn't really a field, but more an associated value.

Yeah, I don't hate this. It might be better, all things considered. I
like having all trait items start with a keyword, probably helps us
with future expansions of the syntax, and avoids the awkward , vs
; quesiton.

This comment has been minimized.

@ticki

ticki Mar 16, 2016

Contributor

It also has a symmetry to type.

@ticki

ticki Mar 16, 2016

Contributor

It also has a symmetry to type.

Show outdated Hide outdated text/0000-fields-in-traits.md
- **The ability to index into fixed-length arrays with a constant
index.** However, it would be best to couple that with a general
overhaul of constant evaluation (and probably an extension of
borrowck to understand expressions of this form more broadly).b

This comment has been minimized.

@ticki

ticki Mar 16, 2016

Contributor

There is a typo here.

@ticki

ticki Mar 16, 2016

Contributor

There is a typo here.

Show outdated Hide outdated text/0000-fields-in-traits.md
the trait and define a field with that name. Sometimes it may be
necessary or desirable to specify the trait explicitly. For those
cases, we introduce a fully qualified field notation which looks like
`x.<Trait<U,V>::f>`.

This comment has been minimized.

@nagisa

nagisa Mar 16, 2016

Contributor

<x as Trait<U, V>>.f?

EDIT: whoops.

@nagisa

nagisa Mar 16, 2016

Contributor

<x as Trait<U, V>>.f?

EDIT: whoops.

This comment has been minimized.

@eddyb

eddyb Mar 16, 2016

Member

x is not supposed to be a type, but an expression, so that form wouldn't necessarily be unambiguous.

@eddyb

eddyb Mar 16, 2016

Member

x is not supposed to be a type, but an expression, so that form wouldn't necessarily be unambiguous.

This comment has been minimized.

@nagisa

nagisa Mar 16, 2016

Contributor

Oh wow, I actually came to like the proposed syntax.

@nagisa

nagisa Mar 16, 2016

Contributor

Oh wow, I actually came to like the proposed syntax.

This comment has been minimized.

@DanielKeep

DanielKeep Mar 17, 2016

Wouldn't the obvious equivalent be (x as Trait<U, V>).f?

@DanielKeep

DanielKeep Mar 17, 2016

Wouldn't the obvious equivalent be (x as Trait<U, V>).f?

This comment has been minimized.

@eddyb

eddyb Mar 17, 2016

Member

No, because casts are always rvalues and as at the type level is a completely unrelated construct.

@eddyb

eddyb Mar 17, 2016

Member

No, because casts are always rvalues and as at the type level is a completely unrelated construct.

This comment has been minimized.

@Manishearth

Manishearth Mar 17, 2016

Member

Might this screw up the grammar? I'm thinking of ambiguities with 1. < foo::CONST >.

@Manishearth

Manishearth Mar 17, 2016

Member

Might this screw up the grammar? I'm thinking of ambiguities with 1. < foo::CONST >.

This comment has been minimized.

@arielb1

arielb1 Mar 18, 2016

Contributor

@Manishearth

No. That works at the tokenizer level.

@arielb1

arielb1 Mar 18, 2016

Contributor

@Manishearth

No. That works at the tokenizer level.

Show outdated Hide outdated text/0000-fields-in-traits.md
field path on the left-hand-side of `()`. In other words, just as
calling a closure located at `a.b.c` must be written `(a.b.c)()` (so
as to avoid ambiguity with calling a method `c` on the path `a.b`), so
must you wrote `(a.b.<Trait::c>)()`; `a.b.<Trait::c>()` will not

This comment has been minimized.

@nagisa

nagisa Mar 16, 2016

Contributor

s/wrote/write/

@nagisa

nagisa Mar 16, 2016

Contributor

s/wrote/write/

This comment has been minimized.

@Ericson2314

Ericson2314 Mar 16, 2016

Contributor

To be clear, the paren restriction could be removed, as no trait can have a field and method with the same name, right?

@Ericson2314

Ericson2314 Mar 16, 2016

Contributor

To be clear, the paren restriction could be removed, as no trait can have a field and method with the same name, right?

This comment has been minimized.

@eddyb

eddyb Mar 16, 2016

Member

Same for calling direct fields vs methods, if we can properly disambiguate at type-checking time.

@eddyb

eddyb Mar 16, 2016

Member

Same for calling direct fields vs methods, if we can properly disambiguate at type-checking time.

This comment has been minimized.

@Jexell

Jexell Mar 16, 2016

You could also perhaps give either fields or methods a priority and introduce a lint.

@Jexell

Jexell Mar 16, 2016

You could also perhaps give either fields or methods a priority and introduce a lint.

This comment has been minimized.

@notriddle

notriddle Mar 17, 2016

Contributor

To be clear, the paren restriction could be removed, as no trait can have a field and method with the same name, right?

Why not?

@notriddle

notriddle Mar 17, 2016

Contributor

To be clear, the paren restriction could be removed, as no trait can have a field and method with the same name, right?

Why not?

This comment has been minimized.

@Nashenas88

Nashenas88 Mar 18, 2016

If we do leave it in, is this the right place to mention that the existing help span should be extended? There's one in place now that will recognize a field is a closure and rewrites your code with the parenthesis as a suggestion.

@Nashenas88

Nashenas88 Mar 18, 2016

If we do leave it in, is this the right place to mention that the existing help span should be extended? There's one in place now that will recognize a field is a closure and rewrites your code with the parenthesis as a suggestion.

Show outdated Hide outdated text/0000-fields-in-traits.md
`x.<Trait<U,V>::f>`.
This is comparable to the associated item notation `<T as
Trait<U,V>>::foo`, but with some differences. First, the `Self` type

This comment has been minimized.

@petrochenkov

petrochenkov Mar 16, 2016

Contributor

Type::field/<Type>::field/<Type as Trait>::field is a very attractive syntax for field projection functions (aka pointers to data members):

struct Person { age: u8 }
let opt_age: Option<u8> = opt_person.map(Person::age);

It would be nice to preserve it while selecting syntax for this RFC.

@petrochenkov

petrochenkov Mar 16, 2016

Contributor

Type::field/<Type>::field/<Type as Trait>::field is a very attractive syntax for field projection functions (aka pointers to data members):

struct Person { age: u8 }
let opt_age: Option<u8> = opt_person.map(Person::age);

It would be nice to preserve it while selecting syntax for this RFC.

@Ericson2314

This comment has been minimized.

Show comment
Hide comment
@Ericson2314

Ericson2314 Mar 16, 2016

Contributor

I like this a lot---it's broadly useful even outside the realm of "virtual structs", and very orthogonal to the listed future work, which are the good smells for this sort of thing.

[Kinda off topic] Another route of generalization is "first class lvalues". I don't know what his would look like, but it might be useful wrt things like map entry API. Teaching the borrow checker that entries for disjoint keys are disjoint would be neat. This is absolutely out of scope for this RFC, but if this is accepted, it opens the door to further exploration in that direction---great!

Contributor

Ericson2314 commented Mar 16, 2016

I like this a lot---it's broadly useful even outside the realm of "virtual structs", and very orthogonal to the listed future work, which are the good smells for this sort of thing.

[Kinda off topic] Another route of generalization is "first class lvalues". I don't know what his would look like, but it might be useful wrt things like map entry API. Teaching the borrow checker that entries for disjoint keys are disjoint would be neat. This is absolutely out of scope for this RFC, but if this is accepted, it opens the door to further exploration in that direction---great!

Show outdated Hide outdated text/0000-fields-in-traits.md
languages. This means that if, e.g., `Circle` wanted to override the
`highlight` method but also call out to the prior version, it can't
easily do so. Super calls are not strictly needed thoug, as one can
always refactor the super call into a free fn.

This comment has been minimized.

@futile

futile Mar 17, 2016

This section contains references to types such as Container and Circle which are not mentioned in the RFC anywhere else. Probably a left-over from previous revisions?

@futile

futile Mar 17, 2016

This section contains references to types such as Container and Circle which are not mentioned in the RFC anywhere else. Probably a left-over from previous revisions?

Show outdated Hide outdated text/0000-fields-in-traits.md
}
impl Trait for Illegal {
x: self.z // ERROR: Private item in public API

This comment has been minimized.

@petrochenkov

petrochenkov Mar 17, 2016

Contributor

How this is different from

impl Trait for Type {
 fn private_field(&mut self) -> &mut FieldType { &self.private_field }
}

from the privacy point of view?
I wouldn't expect private-in-public checks to be applied to these fields at all.
(Type of the field should be checked though.)

@petrochenkov

petrochenkov Mar 17, 2016

Contributor

How this is different from

impl Trait for Type {
 fn private_field(&mut self) -> &mut FieldType { &self.private_field }
}

from the privacy point of view?
I wouldn't expect private-in-public checks to be applied to these fields at all.
(Type of the field should be checked though.)

This comment has been minimized.

@nikomatsakis

nikomatsakis Mar 17, 2016

Contributor

@petrochenkov

How this is different from [a fn that references the field]

It feels different to me because I am projecting out the field itself. Thus I have effectively made the field public. In contrast, with a wrapper function, I am projecting out a method that mediates access to the underlying field.

It is roughly the same argument as with an associated type. Both field mappings and associated types give people another way to name something that already exists. Therefore, we have to respect the privacy rules on that underlying thing. In contrast, defining a method defines a new thing which is implicitly public.

If we had "function aliases", where you just map a function directly to another (rather than wrapping it), I would expect the privacy rules to be stricter there as well.

Type of the field should be checked though.

I guess I did not say that explicitly, but I agree.

@nikomatsakis

nikomatsakis Mar 17, 2016

Contributor

@petrochenkov

How this is different from [a fn that references the field]

It feels different to me because I am projecting out the field itself. Thus I have effectively made the field public. In contrast, with a wrapper function, I am projecting out a method that mediates access to the underlying field.

It is roughly the same argument as with an associated type. Both field mappings and associated types give people another way to name something that already exists. Therefore, we have to respect the privacy rules on that underlying thing. In contrast, defining a method defines a new thing which is implicitly public.

If we had "function aliases", where you just map a function directly to another (rather than wrapping it), I would expect the privacy rules to be stricter there as well.

Type of the field should be checked though.

I guess I did not say that explicitly, but I agree.

This comment has been minimized.

@rkjnsn

rkjnsn Mar 24, 2016

Contributor

@nikomatsakis I disagree. That there is a field of a given type is part of the public interface exposed through the trait, but I would argue where in the struct it is stored, and what it is named there, could easily be considered an implementation detail. I want to have the flexibility to organize my struct (including grouping fields into member structs) without breaking the public interface, which I can't do if the fields are forced to be public.

@rkjnsn

rkjnsn Mar 24, 2016

Contributor

@nikomatsakis I disagree. That there is a field of a given type is part of the public interface exposed through the trait, but I would argue where in the struct it is stored, and what it is named there, could easily be considered an implementation detail. I want to have the flexibility to organize my struct (including grouping fields into member structs) without breaking the public interface, which I can't do if the fields are forced to be public.

This comment has been minimized.

@nikomatsakis

nikomatsakis Mar 29, 2016

Contributor

@rkjnsn

I want to have the flexibility to organize my struct (including grouping fields into member structs) without breaking the public interface, which I can't do if the fields are forced to be public.

This is a strong argument. I've been somewhat reconsidering this point. One difference between the case of fields and the case of associated types is that associated types are true synonyms and normalized, so if we allowed private types to appear in associated type bindings, then we would effectively allow instances of those types to escape into generic functions, which they are not supposed to do.

With fields, somewhat like methods, so long as the type of the field is public, you are only allowing those parts of the value to escape that are designated in the trait. (This was @petrochenkov's original point as well, I believe).

@nikomatsakis

nikomatsakis Mar 29, 2016

Contributor

@rkjnsn

I want to have the flexibility to organize my struct (including grouping fields into member structs) without breaking the public interface, which I can't do if the fields are forced to be public.

This is a strong argument. I've been somewhat reconsidering this point. One difference between the case of fields and the case of associated types is that associated types are true synonyms and normalized, so if we allowed private types to appear in associated type bindings, then we would effectively allow instances of those types to escape into generic functions, which they are not supposed to do.

With fields, somewhat like methods, so long as the type of the field is public, you are only allowing those parts of the value to escape that are designated in the trait. (This was @petrochenkov's original point as well, I believe).

@Manishearth

This comment has been minimized.

Show comment
Hide comment
@Manishearth

Manishearth Mar 17, 2016

Member

Note that as an inheritance system this is not useful for Servo's DOM. This is just a datapoint, not a reason to block it 😄 Otherwise big 👍 , sounds useful.

Member

Manishearth commented Mar 17, 2016

Note that as an inheritance system this is not useful for Servo's DOM. This is just a datapoint, not a reason to block it 😄 Otherwise big 👍 , sounds useful.

@petrochenkov

This comment has been minimized.

Show comment
Hide comment
@petrochenkov

petrochenkov Mar 17, 2016

Contributor

Any plans to incorporate mutability in this RFC?
E.g. if I want to emulate a getter function with a trait field, then I wouldn't want this field to be mutable.
Maybe these fields should even be immutable by default.

trait Tr {
    x: u8, // Immutable field access, "getter"
    mut y: u8, // Mutable field access, "setter/getter"
}
Contributor

petrochenkov commented Mar 17, 2016

Any plans to incorporate mutability in this RFC?
E.g. if I want to emulate a getter function with a trait field, then I wouldn't want this field to be mutable.
Maybe these fields should even be immutable by default.

trait Tr {
    x: u8, // Immutable field access, "getter"
    mut y: u8, // Mutable field access, "setter/getter"
}
@eddyb

This comment has been minimized.

Show comment
Hide comment
@eddyb

eddyb Mar 17, 2016

Member

@petrochenkov That would be great with fields in inherent impls!
It would mean you can have a private field with an immutable public view in an impl, so you can mutate it, but not anyone else.

Member

eddyb commented Mar 17, 2016

@petrochenkov That would be great with fields in inherent impls!
It would mean you can have a private field with an immutable public view in an impl, so you can mutate it, but not anyone else.

@jFransham

This comment has been minimized.

Show comment
Hide comment
@jFransham

jFransham Mar 17, 2016

Big 👍 on this, I personally would prefer that trait fields are not immutable by default, but that mutability is controlled by whether or not the concrete value is mutable. I think if we can work out a general-case disjointness checking solution (the syntax that comes to mind is fn modstigate(self: &Self { field_a }) -> &TypeOfFieldA) then we could keep the semantics of trait fields and struct fields consistent, and use privacy to control field mutability on both (like we do already).

jFransham commented Mar 17, 2016

Big 👍 on this, I personally would prefer that trait fields are not immutable by default, but that mutability is controlled by whether or not the concrete value is mutable. I think if we can work out a general-case disjointness checking solution (the syntax that comes to mind is fn modstigate(self: &Self { field_a }) -> &TypeOfFieldA) then we could keep the semantics of trait fields and struct fields consistent, and use privacy to control field mutability on both (like we do already).

@kylone

This comment has been minimized.

Show comment
Hide comment
@kylone

kylone Mar 17, 2016

@jFransham Just to be clear, "use privacy to control field mutability" means using Cell & RefCell in std::cell, right?

kylone commented Mar 17, 2016

@jFransham Just to be clear, "use privacy to control field mutability" means using Cell & RefCell in std::cell, right?

@pnkfelix

This comment has been minimized.

Show comment
Hide comment
@pnkfelix

pnkfelix Mar 17, 2016

Member

@Manishearth

Note that as an inheritance system this is not useful for Servo's DOM

Just to be clear: would something like the extension described in the Embedded notation and prefix layout section do more to address Servo's use case?

Or do you more broadly mean that we need all the things list in the Other changes section that followed that?

Or do you mean that there is something Servo needs that is not addressed by the items enumerated there?

Member

pnkfelix commented Mar 17, 2016

@Manishearth

Note that as an inheritance system this is not useful for Servo's DOM

Just to be clear: would something like the extension described in the Embedded notation and prefix layout section do more to address Servo's use case?

Or do you more broadly mean that we need all the things list in the Other changes section that followed that?

Or do you mean that there is something Servo needs that is not addressed by the items enumerated there?

@Manishearth

This comment has been minimized.

Show comment
Hide comment
@Manishearth

Manishearth Mar 17, 2016

Member

@pnkfelix embedded notation works pretty well.

Member

Manishearth commented Mar 17, 2016

@pnkfelix embedded notation works pretty well.

@golddranks

This comment has been minimized.

Show comment
Hide comment
@golddranks

golddranks Mar 17, 2016

@jFransham I don't quite understand what you're saying, but traits are basically interfaces. You code against an interface. If you mean by "concrete value" a field in the struct that implements a trait, how could you code generically against the interface, without the trait saying whether the value is mutable or immutable? You can't.

golddranks commented Mar 17, 2016

@jFransham I don't quite understand what you're saying, but traits are basically interfaces. You code against an interface. If you mean by "concrete value" a field in the struct that implements a trait, how could you code generically against the interface, without the trait saying whether the value is mutable or immutable? You can't.

@eddyb

This comment has been minimized.

Show comment
Hide comment
@eddyb

eddyb Mar 17, 2016

Member

@golddranks The mutability depends on whether the value implementing the trait is in a mutable slot or not. This is already the case, e.g. if you write accessors, you can call setters that take &mut self only if the value is in a mutable slot.

Member

eddyb commented Mar 17, 2016

@golddranks The mutability depends on whether the value implementing the trait is in a mutable slot or not. This is already the case, e.g. if you write accessors, you can call setters that take &mut self only if the value is in a mutable slot.

@golddranks

This comment has been minimized.

Show comment
Hide comment
@golddranks

golddranks Mar 17, 2016

@eddyb Ah, I see. Pardon my ignorance.

golddranks commented Mar 17, 2016

@eddyb Ah, I see. Pardon my ignorance.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Mar 17, 2016

Contributor

@petrochenkov

Any plans to incorporate mutability in this RFC?

I did not have any such plans. It's an interesting thought. I sort of wish we declared fields as mut as well, in which case this would be consistent. But we don't.

I think I would be more in favor if we also planned to add a mut keyword to ordinary fields and then to lint against assigning directly to a field (or a projection from a field) unless it is declared as mut. Put another way: you would be able to assign to x.f if (a) x is mutable, as today and (b) f is mutable. If (a) is violated, you get an error (as today). If (b) is violated, the code compiles, but you get a lint warning. Obviously the rules would still be mildly different then but if you followed "best practices" it would be consistent.

Contributor

nikomatsakis commented Mar 17, 2016

@petrochenkov

Any plans to incorporate mutability in this RFC?

I did not have any such plans. It's an interesting thought. I sort of wish we declared fields as mut as well, in which case this would be consistent. But we don't.

I think I would be more in favor if we also planned to add a mut keyword to ordinary fields and then to lint against assigning directly to a field (or a projection from a field) unless it is declared as mut. Put another way: you would be able to assign to x.f if (a) x is mutable, as today and (b) f is mutable. If (a) is violated, you get an error (as today). If (b) is violated, the code compiles, but you get a lint warning. Obviously the rules would still be mildly different then but if you followed "best practices" it would be consistent.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Mar 17, 2016

Contributor

@Manishearth

Note that as an inheritance system this is not useful for Servo's DOM. This

I think you and @pnkfelix hashed this out, but to be clear: as the RFC states, this RFC alone is not intended to solve Servo's "DOM problem", but it is a major building block towards doing so. The section on future work lays out the additional steps that I believe would be needed to make a truly ergonomic DOM implementation. If you think anything else is required, it'd be good to speak up. =)

Contributor

nikomatsakis commented Mar 17, 2016

@Manishearth

Note that as an inheritance system this is not useful for Servo's DOM. This

I think you and @pnkfelix hashed this out, but to be clear: as the RFC states, this RFC alone is not intended to solve Servo's "DOM problem", but it is a major building block towards doing so. The section on future work lays out the additional steps that I believe would be needed to make a truly ergonomic DOM implementation. If you think anything else is required, it'd be good to speak up. =)

@Manishearth

This comment has been minimized.

Show comment
Hide comment
@Manishearth

Manishearth Mar 17, 2016

Member

Yeah, understood. I personally don't really feel Servo needs a better DOM solution at this stage (If it exists, sure, we'd use it, but I don't want to push for it). I'm happy with our current set of hacks, and the only (minor) improvement I'd like would be some layout-guarantees so that the transmutes aren't technically UB.

I was just pointing out that if the motivation behind this was partially due to use cases like Servo's DOM, it doesn't apply cleanly there.

Basically, Servo would need cheap upcasting. I think with this proposal you need to use trait objects to get that effect, if it is even possible.

Member

Manishearth commented Mar 17, 2016

Yeah, understood. I personally don't really feel Servo needs a better DOM solution at this stage (If it exists, sure, we'd use it, but I don't want to push for it). I'm happy with our current set of hacks, and the only (minor) improvement I'd like would be some layout-guarantees so that the transmutes aren't technically UB.

I was just pointing out that if the motivation behind this was partially due to use cases like Servo's DOM, it doesn't apply cleanly there.

Basically, Servo would need cheap upcasting. I think with this proposal you need to use trait objects to get that effect, if it is even possible.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Mar 17, 2016

Contributor

I don't have time to edit the draft now, but I've added a "planned edits" section to the main area.

Contributor

nikomatsakis commented Mar 17, 2016

I don't have time to edit the draft now, but I've added a "planned edits" section to the main area.

@kbknapp

This comment has been minimized.

Show comment
Hide comment
@kbknapp

kbknapp Mar 18, 2016

Huge 👍 I've wanted this for a while but there's no way I could have articulated it that well!

kbknapp commented Mar 18, 2016

Huge 👍 I've wanted this for a while but there's no way I could have articulated it that well!

@nrc

This comment has been minimized.

Show comment
Hide comment
@nrc

nrc Mar 18, 2016

Member

I'm strongly in favour of the core concept here, based on the accessor motivation (I haven't really digested the efficient inheritance angle yet). However, the details give me pause. We are introducing more complexity into the trait system, and for me that needs a really high level of motivation because I think it is getting into over-complex territory already.

Specifically, the disjointness rules, a new kind of qualified path, the rules for which expressions are valid values for the fields in impls, and (to a lesser degree) the syntax questions. All of these seem like detailed, ugly rules which are necessary but unfortunate and make this feature undesirable to me.

I wonder (though I am not hopeful) if there might be a more elegant formulation, since the concept of fields in traits seems natural enough (and desirable).

Member

nrc commented Mar 18, 2016

I'm strongly in favour of the core concept here, based on the accessor motivation (I haven't really digested the efficient inheritance angle yet). However, the details give me pause. We are introducing more complexity into the trait system, and for me that needs a really high level of motivation because I think it is getting into over-complex territory already.

Specifically, the disjointness rules, a new kind of qualified path, the rules for which expressions are valid values for the fields in impls, and (to a lesser degree) the syntax questions. All of these seem like detailed, ugly rules which are necessary but unfortunate and make this feature undesirable to me.

I wonder (though I am not hopeful) if there might be a more elegant formulation, since the concept of fields in traits seems natural enough (and desirable).

@abonander abonander referenced this pull request Mar 18, 2016

Closed

iup-rust and kiss-ui #21

@glaebhoerl

This comment has been minimized.

Show comment
Hide comment
@glaebhoerl

glaebhoerl Mar 19, 2016

Contributor

The idea sounds nice, and the disjointness rules "feel right" to me -- at least at first blush.

Scattered thoughts:

  • Rust's traits can be thought of as having N+1 type parameters, being the explicit ones together with Self, which is implicit. A "supertrait" is usually just the colloquial term for a trait bound on Self, and the RFC only explicitly mentions supertraits. But if I have, say, trait Field2<T: Field1> { let field2: bool; }, do the same disjointness rules apply between the associated fields of Field1 and Field2?

  • For the purposes of disjointness, Trait<Type1> and Trait<Type2> are considered to be unrelated traits, right? Are we sure that there aren't any devils hiding in the interaction of generic traits and disjointness? (And that there aren't any other trait-related features which might have "interesting" interactions?) Is trait Field2: Field1<Type1> + Field1<Type2> handled cleanly? What about trait Field2<Type1, Type2>: Field1<Type1> + Field1<Type2>? What if associated type projections are involved? (My feeling is that there probably aren't any issues, but someone should actually think it through.)

  • Under what circumstances might associated fields be allowed to be ?Sized? Currently we allow the last field in a struct to be a DST. Can an associated field map onto that somehow? Can (unrelatedly) we do zany things like map an associated let field: Trait onto a struct's field: Type where Type: Trait, or a let field: [T] onto a [T; N]?

  • A very benign and occasionally pleasant extension might be to allow specifying the entire type as "the field" in an impl (obviously this only works if it's the only field in the trait, due to disjointness rules). Like this:

    struct Type { /* stuff */ }
    
    trait Trait {
        let field: Type;
    }
    
    impl Trait for Type {
        let field = self;
    }
    

    I can't think of a concrete use case off the top of my head, but I remember having wanted to do this kind of thing occasionally with pointers-to-member in C++. (The functionality offered by trait objects with associated fields feels kinda similar to that of pointers-to-member...)

  • Another thing that sounds really vaguely exciting is the possibility of structural (or "auto") traits which are automatically implemented by structs which have (public) fields of matching names and types. So e.g. (to make up a syntax) the trait struct { x: T, y: T } would range over any struct which has x and y fields of that type. And for tuples, T: (A, B) would mean any tuple or tuple struct with at least two fields -- that is, the equivalent of struct { 1: A, 2: B }, given tuples' positional fields. (I can't seem to decide whether I suspect this would be a quasi-reasonable addition to the language, or an incredibly nontrivial one...)

  • In any case where two concepts are dual to each other and are treated incongruously, my face takes on a questioning expression, and here's no different. Could all of the same ideas from this RFC be extended analogously to enum variants, and not just struct fields? Would it be useful? If not, why not?

Contributor

glaebhoerl commented Mar 19, 2016

The idea sounds nice, and the disjointness rules "feel right" to me -- at least at first blush.

Scattered thoughts:

  • Rust's traits can be thought of as having N+1 type parameters, being the explicit ones together with Self, which is implicit. A "supertrait" is usually just the colloquial term for a trait bound on Self, and the RFC only explicitly mentions supertraits. But if I have, say, trait Field2<T: Field1> { let field2: bool; }, do the same disjointness rules apply between the associated fields of Field1 and Field2?

  • For the purposes of disjointness, Trait<Type1> and Trait<Type2> are considered to be unrelated traits, right? Are we sure that there aren't any devils hiding in the interaction of generic traits and disjointness? (And that there aren't any other trait-related features which might have "interesting" interactions?) Is trait Field2: Field1<Type1> + Field1<Type2> handled cleanly? What about trait Field2<Type1, Type2>: Field1<Type1> + Field1<Type2>? What if associated type projections are involved? (My feeling is that there probably aren't any issues, but someone should actually think it through.)

  • Under what circumstances might associated fields be allowed to be ?Sized? Currently we allow the last field in a struct to be a DST. Can an associated field map onto that somehow? Can (unrelatedly) we do zany things like map an associated let field: Trait onto a struct's field: Type where Type: Trait, or a let field: [T] onto a [T; N]?

  • A very benign and occasionally pleasant extension might be to allow specifying the entire type as "the field" in an impl (obviously this only works if it's the only field in the trait, due to disjointness rules). Like this:

    struct Type { /* stuff */ }
    
    trait Trait {
        let field: Type;
    }
    
    impl Trait for Type {
        let field = self;
    }
    

    I can't think of a concrete use case off the top of my head, but I remember having wanted to do this kind of thing occasionally with pointers-to-member in C++. (The functionality offered by trait objects with associated fields feels kinda similar to that of pointers-to-member...)

  • Another thing that sounds really vaguely exciting is the possibility of structural (or "auto") traits which are automatically implemented by structs which have (public) fields of matching names and types. So e.g. (to make up a syntax) the trait struct { x: T, y: T } would range over any struct which has x and y fields of that type. And for tuples, T: (A, B) would mean any tuple or tuple struct with at least two fields -- that is, the equivalent of struct { 1: A, 2: B }, given tuples' positional fields. (I can't seem to decide whether I suspect this would be a quasi-reasonable addition to the language, or an incredibly nontrivial one...)

  • In any case where two concepts are dual to each other and are treated incongruously, my face takes on a questioning expression, and here's no different. Could all of the same ideas from this RFC be extended analogously to enum variants, and not just struct fields? Would it be useful? If not, why not?

@eddyb

This comment has been minimized.

Show comment
Hide comment
@eddyb

eddyb Mar 19, 2016

Member

A "supertrait" is usually just the colloquial term for a trait bound on Self

It's a lot more than that, Rust is biased on Self because of the efficient implementation strategies for dynamic dispatch.

Trait objects having been exposed as explicit existentials would have likely been much better, because in e.g. exists T,U.(T, U) where T: Add<U> you need one vtable, that for <T as Add<U>>, so you could easily have that as exists T,U.(T, U) where Add(T, U) instead, it's still fast but it's also more flexible than Rust today.
A more palatable syntax could be (@T, @U) where Add(T, U).

Actually, that's pretty much impl Trait territory, but either way, you'd need to delay such a change until 2.0 or 3.0 and convince everyone it's a good idea.

Could all of the same ideas from this RFC be extended analogously to enum variants, and not just struct fields?

What do you have in mind? Common fields in enums are desired, but abstracting over variants is a bit trickier and I haven't seen anyone mentioning it until now.

Member

eddyb commented Mar 19, 2016

A "supertrait" is usually just the colloquial term for a trait bound on Self

It's a lot more than that, Rust is biased on Self because of the efficient implementation strategies for dynamic dispatch.

Trait objects having been exposed as explicit existentials would have likely been much better, because in e.g. exists T,U.(T, U) where T: Add<U> you need one vtable, that for <T as Add<U>>, so you could easily have that as exists T,U.(T, U) where Add(T, U) instead, it's still fast but it's also more flexible than Rust today.
A more palatable syntax could be (@T, @U) where Add(T, U).

Actually, that's pretty much impl Trait territory, but either way, you'd need to delay such a change until 2.0 or 3.0 and convince everyone it's a good idea.

Could all of the same ideas from this RFC be extended analogously to enum variants, and not just struct fields?

What do you have in mind? Common fields in enums are desired, but abstracting over variants is a bit trickier and I haven't seen anyone mentioning it until now.

@golddranks

This comment has been minimized.

Show comment
Hide comment
@golddranks

golddranks Mar 21, 2016

@nikomatsakis

I did not have any such plans. It's an interesting thought.

What do you think about having a way to expose an immutable view to a private field that would be implementable according to the privacy rules? (Like @eddyb said)

Limiting the mutability in public field access in trait fields wouldn't make sense expect as a lint, because the loss of parametricity caused by specialization allows you to circumvent the limits, but exposing read access to private fields would work robustly, because only those with access to the private fields would be able to implement such traits, wouldn't it?

With the current proposal if I wanted to have something akin to "immutable field semantics", I'd have to make a private field to store the value and then provide a getter – which interacts poorly with the borrow checker like pointed out in the RFC. So it would be nice to be able to expose read-only values too with field-like semantics.

golddranks commented Mar 21, 2016

@nikomatsakis

I did not have any such plans. It's an interesting thought.

What do you think about having a way to expose an immutable view to a private field that would be implementable according to the privacy rules? (Like @eddyb said)

Limiting the mutability in public field access in trait fields wouldn't make sense expect as a lint, because the loss of parametricity caused by specialization allows you to circumvent the limits, but exposing read access to private fields would work robustly, because only those with access to the private fields would be able to implement such traits, wouldn't it?

With the current proposal if I wanted to have something akin to "immutable field semantics", I'd have to make a private field to store the value and then provide a getter – which interacts poorly with the borrow checker like pointed out in the RFC. So it would be nice to be able to expose read-only values too with field-like semantics.

@glaebhoerl

This comment has been minimized.

Show comment
Hide comment
@glaebhoerl

glaebhoerl Mar 21, 2016

Contributor

What do you have in mind?

I was hoping to provoke someone else into figuring that out for me :P

But let's see. The symmetry between product and sum types (structs and enums) is that construction for one looks similar to access for the other. So the dual to accessing a struct field (what this RFC allows) is creating an enum variant.

So you'd have traits with associated enum variants, which implementors of those traits map onto particular variants of the concrete enum (as with struct fields, these could be a chain of variants and sub-variants), and clients of the trait get to construct those variants through the abstract interface.

What might this be useful for?

The first possibility which occurs to me is error handling. You could have a trait listing possible error conditions (as variants), and the library could support returning its errors as any enum which can represent those cases.

Contributor

glaebhoerl commented Mar 21, 2016

What do you have in mind?

I was hoping to provoke someone else into figuring that out for me :P

But let's see. The symmetry between product and sum types (structs and enums) is that construction for one looks similar to access for the other. So the dual to accessing a struct field (what this RFC allows) is creating an enum variant.

So you'd have traits with associated enum variants, which implementors of those traits map onto particular variants of the concrete enum (as with struct fields, these could be a chain of variants and sub-variants), and clients of the trait get to construct those variants through the abstract interface.

What might this be useful for?

The first possibility which occurs to me is error handling. You could have a trait listing possible error conditions (as variants), and the library could support returning its errors as any enum which can represent those cases.

@glaebhoerl

This comment has been minimized.

Show comment
Hide comment
@glaebhoerl

glaebhoerl Mar 21, 2016

Contributor

Unrelatedly:

While associated struct fields sound interesting and compelling in the abstract, I'd be curious to see more real-world examples of what people would actually use them for!

Contributor

glaebhoerl commented Mar 21, 2016

Unrelatedly:

While associated struct fields sound interesting and compelling in the abstract, I'd be curious to see more real-world examples of what people would actually use them for!

@critiqjo

This comment has been minimized.

Show comment
Hide comment
@critiqjo

critiqjo Mar 21, 2016

While associated struct fields sound interesting and compelling in the abstract, I'd be curious to see more real-world examples of what people would actually use them for!

I'm planning to write a very generic Raft library, and it has multiple "message" types that need to be serialized. If the choice of serialization library (serde vs rustc-serialize vs ...?) is not up to the user, then it's not generic enough, and if fields are accessed and modified using accessors, it'd be very ugly...

critiqjo commented Mar 21, 2016

While associated struct fields sound interesting and compelling in the abstract, I'd be curious to see more real-world examples of what people would actually use them for!

I'm planning to write a very generic Raft library, and it has multiple "message" types that need to be serialized. If the choice of serialization library (serde vs rustc-serialize vs ...?) is not up to the user, then it's not generic enough, and if fields are accessed and modified using accessors, it'd be very ugly...

@Ericson2314 Ericson2314 referenced this pull request Mar 21, 2016

Merged

Allocators, take III #1398

12 of 25 tasks complete
@jeanm

This comment has been minimized.

Show comment
Hide comment
@jeanm

jeanm Mar 22, 2016

While associated struct fields sound interesting and compelling in the abstract, I'd be curious to see more real-world examples of what people would actually use them for!

Not having to write getter/setter methods for fields would be a big plus for me. Every time I have to write them explicitly I feel like I'm using Java.

jeanm commented Mar 22, 2016

While associated struct fields sound interesting and compelling in the abstract, I'd be curious to see more real-world examples of what people would actually use them for!

Not having to write getter/setter methods for fields would be a big plus for me. Every time I have to write them explicitly I feel like I'm using Java.

@carols10cents carols10cents added this to Merge proposed in Tracker Apr 26, 2017

@gnzlbg

This comment has been minimized.

Show comment
Hide comment
@gnzlbg

gnzlbg May 3, 2017

Contributor

Say I have

trait Point<T: FloatingPoint> {
  x: T;
  y: T;
}

Can I implement it for:

struct Some2DPoint {
  xs: [f32; 2]
}

to map Point::x to xs[0] and Point::y to xs[1] ?

Contributor

gnzlbg commented May 3, 2017

Say I have

trait Point<T: FloatingPoint> {
  x: T;
  y: T;
}

Can I implement it for:

struct Some2DPoint {
  xs: [f32; 2]
}

to map Point::x to xs[0] and Point::y to xs[1] ?

@glaebhoerl

This comment has been minimized.

Show comment
Hide comment
@glaebhoerl

glaebhoerl May 3, 2017

Contributor

I think we should support xs.0, xs.1, etc. for fixed-sized arrays.

Contributor

glaebhoerl commented May 3, 2017

I think we should support xs.0, xs.1, etc. for fixed-sized arrays.

@burdges

This comment has been minimized.

Show comment
Hide comment
@burdges

burdges May 3, 2017

I'm uncomfortable with xs.0 being equivalent to xs[0] since tuples are so different from arrays. I suppose you mean :

It's hard to make this code compile without adding magic to IndexMut but if another syntax like xs.0 or xs.array_index(0) could be magic from the get go.

let mut x = [0u8; 2];
let y = &mut x[0];
let z = &mut x[1];

It's unlikely const dependent types will make this code compile somehow?

burdges commented May 3, 2017

I'm uncomfortable with xs.0 being equivalent to xs[0] since tuples are so different from arrays. I suppose you mean :

It's hard to make this code compile without adding magic to IndexMut but if another syntax like xs.0 or xs.array_index(0) could be magic from the get go.

let mut x = [0u8; 2];
let y = &mut x[0];
let z = &mut x[1];

It's unlikely const dependent types will make this code compile somehow?

@glaebhoerl

This comment has been minimized.

Show comment
Hide comment
@glaebhoerl

glaebhoerl May 3, 2017

Contributor

I'm uncomfortable with xs.0 being equivalent to xs[0] since tuples are so different from arrays.

Homogenous tuples are not different at all from fixed-sized arrays.

Contributor

glaebhoerl commented May 3, 2017

I'm uncomfortable with xs.0 being equivalent to xs[0] since tuples are so different from arrays.

Homogenous tuples are not different at all from fixed-sized arrays.

@burdges

This comment has been minimized.

Show comment
Hide comment
@burdges

burdges May 9, 2017

Meh. I suspect you'll encounter trouble writing xs.0 == ys.0 if xs: [u8; ys::LENGTH] then because otherwise you inherit baggage from IndexMut.

burdges commented May 9, 2017

Meh. I suspect you'll encounter trouble writing xs.0 == ys.0 if xs: [u8; ys::LENGTH] then because otherwise you inherit baggage from IndexMut.

@burdges

This comment has been minimized.

Show comment
Hide comment
@burdges

burdges May 9, 2017

I think trait field syntax might help in method calls to support partial borrowing ala #1215.

trait Foo {
    position: usize,
    slice: &[u8],
    fn tweak(&mut self.position, &'a self.slice) -> &'a [u8];
}

burdges commented May 9, 2017

I think trait field syntax might help in method calls to support partial borrowing ala #1215.

trait Foo {
    position: usize,
    slice: &[u8],
    fn tweak(&mut self.position, &'a self.slice) -> &'a [u8];
}
@glaebhoerl

This comment has been minimized.

Show comment
Hide comment
@glaebhoerl

glaebhoerl May 23, 2017

Contributor

Meh. I suspect you'll encounter trouble writing xs.0 == ys.0 if xs: [u8; ys::LENGTH] then because otherwise you inherit baggage from IndexMut.

I don't understand, could you elaborate? In what way would this differ from how the analogous thing works for homogenous tuples? How does IndexMut enter into it?

Contributor

glaebhoerl commented May 23, 2017

Meh. I suspect you'll encounter trouble writing xs.0 == ys.0 if xs: [u8; ys::LENGTH] then because otherwise you inherit baggage from IndexMut.

I don't understand, could you elaborate? In what way would this differ from how the analogous thing works for homogenous tuples? How does IndexMut enter into it?

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis May 25, 2017

Contributor

OK, so, I've been thinking about this RFC for some time, but each time I start to write a comment in an effort to get it "restarted", I wind up getting side-tracked. Therefore, I am taking a different tack. I've created a custom repo dedicated to this RFC. I've created issues for all the major comments I saw in the thread, and tagged them somewhat with my estimate of their priority:

https://github.com/nikomatsakis/fields-in-traits-rfc

I would love to get feedback, particularly on the P-essential issues.

I think at this point I've basically decided to adopt the following:

There were some objections from @rust-lang/lang members to adopting let syntax, but I think that on this thread the idea has been universally popular. If you think it's a bad idea, though, I encourage you to comment in nikomatsakis/fields-in-traits-rfc#3.

Contributor

nikomatsakis commented May 25, 2017

OK, so, I've been thinking about this RFC for some time, but each time I start to write a comment in an effort to get it "restarted", I wind up getting side-tracked. Therefore, I am taking a different tack. I've created a custom repo dedicated to this RFC. I've created issues for all the major comments I saw in the thread, and tagged them somewhat with my estimate of their priority:

https://github.com/nikomatsakis/fields-in-traits-rfc

I would love to get feedback, particularly on the P-essential issues.

I think at this point I've basically decided to adopt the following:

There were some objections from @rust-lang/lang members to adopting let syntax, but I think that on this thread the idea has been universally popular. If you think it's a bad idea, though, I encourage you to comment in nikomatsakis/fields-in-traits-rfc#3.

@crumblingstatue

This comment has been minimized.

Show comment
Hide comment
@crumblingstatue

crumblingstatue Jun 17, 2017

#275 might be a good companion for this, as it would allow private trait fields that could be used by the underlying implementation of provided methods, but not accessible by users, allowing better control of invariants.

crumblingstatue commented Jun 17, 2017

#275 might be a good companion for this, as it would allow private trait fields that could be used by the underlying implementation of provided methods, but not accessible by users, allowing better control of invariants.

@alexreg

This comment has been minimized.

Show comment
Hide comment
@alexreg

alexreg Jan 21, 2018

No progress on this still...?

alexreg commented Jan 21, 2018

No progress on this still...?

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 25, 2018

Contributor

I am nominated this RFC to discuss in the @rust-lang/lang meeting. In particular, I'd like to decide how it fits in our overall priorities and what we ought to do with it.

I also owe some updates (well, perhaps on the dedicated repo) so discuss a few shortcomings of the RFC that I think still need to be addressed, but hopefully that'll come soon.

Contributor

nikomatsakis commented Jan 25, 2018

I am nominated this RFC to discuss in the @rust-lang/lang meeting. In particular, I'd like to decide how it fits in our overall priorities and what we ought to do with it.

I also owe some updates (well, perhaps on the dedicated repo) so discuss a few shortcomings of the RFC that I think still need to be addressed, but hopefully that'll come soon.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 26, 2018

Contributor

@rfcbot fcp postpone

OK, after some discussion in the @rust-lang/lang meeting, it seemed clear that while we are still interested in a change like this, we don't have the bandwidth to push this through right now, so we're going to postpone the change.

I'm going to keep the repo open and also try to catch up on the conversation there and highlight some of the most important open questions though.

If anyone is up for it, I'd be interested in working closely with someone to keep the design going, so we can perhaps revisit it once things are calming down.

Contributor

nikomatsakis commented Jan 26, 2018

@rfcbot fcp postpone

OK, after some discussion in the @rust-lang/lang meeting, it seemed clear that while we are still interested in a change like this, we don't have the bandwidth to push this through right now, so we're going to postpone the change.

I'm going to keep the repo open and also try to catch up on the conversation there and highlight some of the most important open questions though.

If anyone is up for it, I'd be interested in working closely with someone to keep the design going, so we can perhaps revisit it once things are calming down.

@rfcbot

This comment has been minimized.

Show comment
Hide comment
@rfcbot

rfcbot Jan 26, 2018

Team member @nikomatsakis has proposed to postpone this. The next step is review by the rest of the tagged teams:

No concerns currently listed.

Once these reviewers reach consensus, this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

rfcbot commented Jan 26, 2018

Team member @nikomatsakis has proposed to postpone this. The next step is review by the rest of the tagged teams:

No concerns currently listed.

Once these reviewers reach consensus, this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@kevincox

This comment has been minimized.

Show comment
Hide comment
@kevincox

kevincox Jan 28, 2018

If anyone is up for it, I'd be interested in working closely with someone to keep the design going, so we can perhaps revisit it once things are calming down.

I don't know exactly what this would entail but I have run into multiple use cases for this and would be glad to work on it as a new rust contributor.

kevincox commented Jan 28, 2018

If anyone is up for it, I'd be interested in working closely with someone to keep the design going, so we can perhaps revisit it once things are calming down.

I don't know exactly what this would entail but I have run into multiple use cases for this and would be glad to work on it as a new rust contributor.

@rfcbot

This comment has been minimized.

Show comment
Hide comment
@rfcbot

rfcbot Jan 31, 2018

🔔 This is now entering its final comment period, as per the review above. 🔔

rfcbot commented Jan 31, 2018

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot

This comment has been minimized.

Show comment
Hide comment
@rfcbot

rfcbot Jan 31, 2018

🔔 This is now entering its final comment period, as per the review above. 🔔

rfcbot commented Jan 31, 2018

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot

This comment has been minimized.

Show comment
Hide comment
@rfcbot

rfcbot Jan 31, 2018

🔔 This is now entering its final comment period, as per the review above. 🔔

rfcbot commented Jan 31, 2018

🔔 This is now entering its final comment period, as per the review above. 🔔

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 31, 2018

Contributor

@kevincox can we maybe schedule some time to chat? reach out over gitter or IRC or e-mail maybe?

Contributor

nikomatsakis commented Jan 31, 2018

@kevincox can we maybe schedule some time to chat? reach out over gitter or IRC or e-mail maybe?

@vi vi referenced this pull request Feb 1, 2018

Closed

Duplicate messages by rfcbot. #178

@aturon aturon removed the I-nominated label Feb 8, 2018

@rfcbot

This comment has been minimized.

Show comment
Hide comment
@rfcbot

rfcbot Feb 10, 2018

The final comment period is now complete.

rfcbot commented Feb 10, 2018

The final comment period is now complete.

@rfcbot

This comment has been minimized.

Show comment
Hide comment
@rfcbot

rfcbot Feb 10, 2018

The final comment period is now complete.

rfcbot commented Feb 10, 2018

The final comment period is now complete.

@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Feb 14, 2018

Member

Closing as postponed; activity should happen on the dedicated repo.

Member

aturon commented Feb 14, 2018

Closing as postponed; activity should happen on the dedicated repo.

@aturon aturon closed this Feb 14, 2018

@kevincox

This comment has been minimized.

Show comment
Hide comment
@kevincox

kevincox Mar 6, 2018

I created https://internals.rust-lang.org/t/fields-in-traits/6933 to further discuss use cases. I started it off with some broad categories but would be interested in hearing more, and more specific use cases.

kevincox commented Mar 6, 2018

I created https://internals.rust-lang.org/t/fields-in-traits/6933 to further discuss use cases. I started it off with some broad categories but would be interested in hearing more, and more specific use cases.

@Centril Centril added the postponed label Mar 7, 2018

@eddyb eddyb referenced this pull request May 25, 2018

Open

RFC: Delegation #2393

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment