Rust: implement inherent associated items (see RFC 195).

Created on 5 Sep 2013  Â·  21Comments  Â·  Source: rust-lang/rust

This issue is tracking RFC 195's inherent associated items

Original description follows.

When developing a type-parametric impl, I found myself writing code somewhat like this:

    struct Grammar<T, NT> { ... }

    impl<T:Clone,NT:Eq+Hash+Clone+Primable> Grammar<T,NT> {
        fn to_nt_map(&self) -> HashMap<NT, ~[Prod<T,NT>]>
        {
            type Rules = ~[Prod<T,NT>];
            type NTMap = HashMap<NT, Rules>;        
          ...
        }

        fn from_nt_map(start: &NT, rules: &HashMap<NT, ~[Prod<T,NT>]>)
            -> Grammar<T,NT>
        {
            type Rules = ~[Prod<T,NT>];
            type NTMap = HashMap<NT, Rules>;
          ...
        }

        pub fn eliminate_left_recursion(&self) -> Grammar<T,NT>
        {
          ...
        }

        ...

    }

I cannot make a type definition for HashMap<NT, ~[Prod<T,NT>]> outside of the impl because it then those free references to NT and T would be unbound.

And I cannot put a type definition within the impl, even an impl for a struct such as this (it simply does not parse with the current grammar).

(Being able to put type definitions within impls will probably arise naturally from #5033, when we get around to that. But that is nonetheless a separate issue from this: Associated Types (and Associated Items) are about enabling certain patterns for the _user_ of a trait, while this ticket describes a convenience for the _implementor_ of a struct.)

A-associated-items B-RFC-approved C-tracking-issue T-lang

Most helpful comment

Any developments on this lately?

All 21 comments

Nominating; is backwards compatible. I can try and take this on if we decide we want it.

(type aliases would need to preceed all methods)

@cmr said "(type aliases would need to preceed all methods)"

why? To my knowledge there is no such ordering constraint for type aliases within a mod item, so why would an impl item require this?

@pnkfelix yikes, you're right. I think they should be. Why? Because:

#[crate_type="lib"];

mod bar {
    fn foo() -> T {
        32i
    }
    type T = int;
}

is crazy.

Why is that less crazy than

fn foo() { bar() }

fn bar() {}

?

I cede.

On Tue, Dec 31, 2013 at 1:05 AM, Huon Wilson [email protected]:

Why is that less crazy than

fn foo() { bar() }
fn bar() {}

?

—
Reply to this email directly or view it on GitHubhttps://github.com/mozilla/rust/issues/8995#issuecomment-31385141
.

assigning P-low priority (is backwards compatible going foward, as cmr said).

Triage: How does this interact with Associated Types? At least a new syntax would probably have to be chosen.

I think that this feature request is actually satisfied by the Associated Items RFC.

In particular, the section "inherent associated items" of RFC 59 implies (to me) that you can write the exact example that I had asked for.

(I did write in the issue description that this feature request is distinct from associated types, but nonetheless, it seems that the author of RFC 59 decided that it was a natural feature to include.)

So, this now seems to be a subissue of #17307.

I will change the title to "implement inherent associated items."

Hello, I hope this the right place to ask for my request.

Associated types currently only work with traits.
I think they are also useful for structs. Is there a reason for the current limitation ?

pub struct GenericStruct<A, B> {
    fa : A,
    fb : B,
}

struct GenericResult<A, B> {
    fa : A,
    fb : B,
}

impl <A, B> GenericStruct<A, B> {


    // I d like to write
    // type Result = Option<GenericResult<A, B>>;
    // and use it in the code

    fn new(a: A, b : B) -> Option<GenericResult<A, B>> {
        Some(GenericResult {fa: a, fb : b})

    }
}

I'm going to tag this with the tags from https://github.com/rust-lang/rust/issues/8995 since it was closed without this being implemented.

@steveklabnik I think you meant to reference #17307 rather than #8995, which is this issue.

note that inherent associated consts work perfectly fine today

#[derive(Debug)]
struct Vector {
    x: f32,
    y: f32,
    z: f32,
}

impl Vector {
    const ZERO: Self = Vector { x: 0.0, y: 0.0, z: 0.0 };

    fn new(x: f32, y: f32, z: f32) -> Self {
        Vector {
            x, y, z
        }
    }
}

@nikomatsakis Is it right to assume that this can't be implemented without lazy normalization?

It would be good to link to this issue in the error message for https://doc.rust-lang.org/nightly/error-index.html#E0202, as it's not immediately clear that this is supposed to be supported.

Any developments on this lately?

Ran into this limitation today. A simplified example of what I'm trying to do:

trait GenericBackend {
    type ParentObject: GenericParentObject<Self>;
    type ChildObject: GenericChildObject<Self>;
    fn parent() -> Self::ParentObject;
}
trait GenericParentObject<Backend: GenericBackend> {
    fn get_children(&self) -> Vec<Backend::ChildObject>;
}
trait GenericChildObject<Backend: GenericBackend> {
}

Defining the traits works, but trying to impl them leads to an error referencing this issue.

Would like to see this implemented!

Nevermind. What I was trying to do works. I just put "impl MyStruct" instead of "impl MyTrait for MyStruct"...

Blocked on https://github.com/rust-lang/rust/issues/60471 (Lazy normalization).

Any updates?

It would be great to get this in some form, it can make generic programming a lot easier.

Suppose I have a generic struct, and I need to implement several functions on it which all refer to the same "complex" type in their return parameters or arguments, and the type depends on generic parameters. This is a pretty common situation. Naturally I'd like to give that type a nice name and avoid typing it repeatedly.

But, there is no where for that declaration to go if it depends on the generic parameters of the struct.

  • It cannot go in the struct declaration itself because type aliases in a struct are not allowed.
  • It cannot go in the inherent impl, because of this issue.
  • It cannot even be a type alias defined in a function body, "because it depends on an outer parameter"

It seems I have to either
(1) Make an entirely new trait just for this, and make my type an associated type of that trait
(2) Use a macro
(3) Just give up and type it out repeatedly

It's frustrating because in other languages there are better ways

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nikomatsakis picture nikomatsakis  Â·  340Comments

nikomatsakis picture nikomatsakis  Â·  268Comments

thestinger picture thestinger  Â·  234Comments

Mark-Simulacrum picture Mark-Simulacrum  Â·  681Comments

Leo1003 picture Leo1003  Â·  898Comments