rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
99.23k stars 12.81k forks source link

Tracking issue for inherent associated types #8995

Open pnkfelix opened 11 years ago

pnkfelix commented 11 years ago

This is a tracking issue for the "inherent associate type" part of "inherent associated items" part of the RFC 195 "associated items"

About tracking issues

Tracking issues are used to record the overall progress of implementation. They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions. A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature. Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.

Original description

(This code is written in ancient version of Rust, and is not meant to be used directly.)

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.)

Steps

Unresolved Questions

Implementation history

emberian commented 10 years ago

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

emberian commented 10 years ago

(type aliases would need to preceed all methods)

pnkfelix commented 10 years ago

@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?

emberian commented 10 years ago

@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.

huonw commented 10 years ago

Why is that less crazy than

fn foo() { bar() }

fn bar() {}

?

emberian commented 10 years ago

I cede.

On Tue, Dec 31, 2013 at 1:05 AM, Huon Wilson notifications@github.comwrote:

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 .

pnkfelix commented 10 years ago

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

reem commented 10 years ago

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

pnkfelix commented 10 years ago

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.)

pnkfelix commented 10 years ago

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

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

rohel01 commented 9 years ago

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})

    }
}
steveklabnik commented 7 years ago

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.

yodaldevoid commented 6 years ago

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

tinaun commented 6 years ago

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
        }
    }
}
eddyb commented 6 years ago

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

varkor commented 5 years ago

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.

alexreg commented 5 years ago

Any developments on this lately?

ColonelThirtyTwo commented 5 years ago

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"...

petrochenkov commented 5 years ago

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

zamazan4ik commented 4 years ago

Any updates?

cbeck88 commented 4 years ago

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 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

fu5ha commented 2 years ago

For the sake of updating status for people driving by, since it wasn't even linked to this issue at all, the latest progress I believe was made in #82516 which implemented the basics of defining inherent associated types but does not allow their use yet.

chichid commented 2 years ago

Wow this issue is open since 2013. Does anyone know when it's going to make it to stable?

crlf0710 commented 2 years ago

For the sake of updating status for people driving by, since it wasn't even linked to this issue at all, the latest progress I believe was made in #82516 which implemented the basics of defining inherent associated types but does not allow their use yet.

Well it is :) that PR has F-inherent_associated_types label and this tracking issue listed it in the "Implementation History" section.

Does anyone know when it's going to make it to stable?

It's not yet implemented :(

crumblingstatue commented 2 years ago

This feature could use a form of doc(inline) for rustdoc, so when defining associated types that are only reachable from there, the documentation for the type would still be accessible.

crumblingstatue commented 2 years ago

For example, here is rendered documentation for "associated enums" for the C++ API, sf::BlendMode: image The rendered documentation for the Rust binding, using the experimental associated_types feature: image

Ideally, the type definition could be inlined when doc(inline) attribute is present on the associated type item.

Optionally, there could be an automatic inlining, similar to when re-exports re-export something that is only reachable through that re-export, the docs get inlined without having to do anything special.

peku33 commented 1 year ago

Were there any changes made to this in one of last releases?

struct Foo {
    bar: Self::Bar,
}
impl Foo {
    pub type Bar = usize;
}

used to work a couple of nightly releases ago.

Now it fails to compile with error:

error[E0391]: cycle detected when computing predicates of `Foo`
  --> src\main.rs:5:1
   |
5  | struct Foo {
   | ^^^^^^^^^^
   |
note: ...which requires computing predicates of `Foo`...
  --> src\main.rs:5:1
   |
5  | struct Foo {
   | ^^^^^^^^^^
note: ...which requires computing inferred outlives predicates of `Foo`...
  --> src\main.rs:5:1
   |
5  | struct Foo {
   | ^^^^^^^^^^
   = note: ...which requires computing the inferred outlives predicates for items in this crate...
note: ...which requires computing type of `Foo::bar`...
  --> src\main.rs:6:5
   |
6  |     bar: Self::Bar,
   |     ^^^^^^^^^^^^^^
note: ...which requires computing normalized predicates of `Foo`...
  --> src\main.rs:5:1
   |
5  | struct Foo {
   | ^^^^^^^^^^
   = note: ...which again requires computing predicates of `Foo`, completing the cycle
note: cycle used when collecting item types in top-level module
flouet-company commented 1 year ago

I am just curious about the status of this issue. Is someone working on this or has someone made any progress in this space?

fmease commented 1 year ago

There's been a recent series of PRs that work towards fully implementing inherent associated types by @fee1-dead, @cjgillot and me.

I highly suspect that the last one on that list (#105961) broke the code posted above. @peku33, could you please open an issue for the cycle error and tag me? Thanks. Note however that inherent_associated_types is still an incomplete feature and thus it's likely to break every so often.

Is someone working on this or has someone made any progress in this space?

@flouet-company, I'm assigned to several issues related to IATs and I'm in close contact with some members of T-types in order to properly implement inherent associated types.

jhpratt commented 1 year ago

I'd just like to say thank you to you three for working on this feature! I know it's not simple, but it's something a lot of people will appreciate when it's eventually completed.

Cypher1 commented 1 year ago

This seems particularly important for resolving 'clippy::type_complexity' when using large types inside parameterized types with multiple arguments.

Normally we'd use a type Foo = Bar<A, B, C>; but in a generic type, those types may not be accessible except via more type parameters, leading to new complex types.

Keep to hear more about blockers :)

fmease commented 1 year ago

Keep to hear more about blockers

The most recent major blocker is fixing #108491 which is not easy it seems. Basically, you cannot use inherent associated types inside of structs, enums, unions or where clauses (as opposed to function bodies, constants and type aliases) and some function signatures without encountering a cycle error first. According to my current understanding this is due to architectural limitations in the compiler (see this semi-related Zulip topic, cc #22519 the equivalent for trait assoc tys).

Since #109410 got merged, I'm investigating approaches to solve this in a proper way without too much rework.