rust-lang/rust

Meta tracking issue for `impl Trait`

Centril opened this issue ยท 14 comments

This issue tracks the progress of impl Trait in general.

This issue is not for discussion about specific extensions to impl Trait and only exists to provide links to other places that track the progress of specific issues. If you wish to discuss some subject related to impl Trait, please find an existing appropriate issue below or create an new issue and comment here with a link to the newly created issue.


The impl Trait related issues currently on deck are as follows:

  • Label A-impl-trait
  • Permit type Foo = impl Bar;. #63063
    • Permit type Foo = impl Bar; in trait definitions. #29661
  • In const and static items and let bindings. #63065
  • Member constraints in region inference: #61997
  • Existential lifetimes. #60670
  • Support lifetime elision in argument position. #49287
  • Should we allow impl Trait after -> in fn types or parentheses sugar? #45994
  • Do we have to impose a DAG across all functions to allow for auto-safe leakage, or can we use some kind of deferral.
  • Should we permit specifying types if some parameters are implicit and some are explicit? e.g., fn foo<T>(x: impl Iterator<Item = T>>)?
    • Current behavior: An error to specify types
    • Other alternatives: [treat impl Trait as arguments in the list, permitting migration]
  • Some concerns about nested impl Trait usage

Open RFCs:

None.

#65481 Allow impl Trait in trait method return values.

What about impl Trait implementing Traits?

trait Trait {...}
impl Trait for impl AnotherTrait {...}

@sighoya: Each occurence of impl MyTrait produces a unique type (e.g. fn foo() -> impl MyTrait and fn bar() -> impl MyTrait do not return the same type).

This means that impl Trait for impl AnotherTrait {...} would be almost completely useless - it would create a new type, implement a type for it, but give you no way of referring to that type.

You might be thinking of type-alias-impl-trait (e.g. type Foo = impl MyTrait). However, using these types in impl blocks is explicitly ruled out by the RFC

CryZe commented

Well in that position, impl Trait would be a generic T with the trait as the bound <T: Trait>, so

impl Trait for impl AnotherTrait { ... }

desugars to

impl<T: AnotherTrait> Trait for T { ... }

Thank you both,

I think the difference between a impl Trait and a dyn Trait is that the first one is a design time existential even in argument position which get monomorphized at compile time, the latter is a compile time existential which gets monomorphized at runtime.

They should both behave mostly the same in my eyes. Implementing by an impl Trait or dyn Trait should state that every T bounded by this trait implements the trait being implemented.
If this is done twice:

impl Trait for impl AnotherTrait { ... }
impl<T: AnotherTrait> Trait for T { ... }
//or
impl Trait for dyn AnotherTrait { ... }
impl<T: AnotherTrait> Trait for T { ... }

then, the decision is made in favor for the implementation dependent on the given context.

impl Trait for dyn AnotherTrait { ... }

What would this even mean? How do you implement something for type the compiler can't know?

CryZe commented

That's already a thing. It implements it for the trait object.

@sighoya @Aaron1011 @mark-i-m @CryZe This issue is not for general discussion about impl Trait. It's only intended to collect links.

This issue is not for discussion about specific extensions to impl Trait and only exists to provide links to other places that track the progress of specific issues. If you wish to discuss some subject related to impl Trait, please find an existing appropriate issue below or create an new issue and comment here with a link to the newly created issue.

@Centril

Permit type Foo = impl Bar; in trait definitions

This links to #29661 which seems to be about setting associated type defaults, whereas I understood the text to mean something like this:

trait SomeTrait {
    type Foo: Bar;

    fn foo() -> Self::Foo;
}

impl SomeTrait for X {
    type Foo = impl Bar;

    fn foo() -> Self::Foo { ... }
}

I didn't perceive #29661 to be about this use-case, but instead about something different:

trait SomeTrait {
    type Foo: Bar = SomeSpecificBar;
}

I understood "type Foo = impl Bar in trait definitions" to mean my first example and to be one of the end goals of impl Trait. Is there an issue tracking that specific feature that can be linked to?

Trait definitions is your second example, covered by #29661. Your first example is trait implementations, which is covered by RFC 2515 (#63063), specifically the last example of RFC 2515 ยง Guide-level explanation ยง Type alias, and it currently works on nightly with #![feature(type_alias_impl_trait)].

Thanks @Nemo157. I would find amendment to the issue text here to make clear that the link to #63063 also encompasses trait implementations and that the sub-link to #29661 is only about associated type defaults helpful. At the moment, the implication of the text is that #63063 is only about "bare" type aliases and #29661 is about impl Trait in associated types.

Hello, does this include allowing impl Trait in structs? (something RFC2071 may have solved)

E.g. -

struct Session {
    client: websocket::sync::Client<impl websocket::sync::Stream>
}
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
   --> src/main.rs:139:37
    |
139 |     client: websocket::sync::Client<impl websocket::sync::Stream>,
    |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The current workaround for doing this is quite unergonomic -

use anyhow::Result;
use websocket;

fn main() -> Result<()> {
    let session = create_session()?;
    Ok(())
}

struct Session<T: websocket::sync::Stream> {
    client: websocket::sync::Client<T>,
}

fn create_session() -> Result<Session<impl websocket::sync::Stream>> {
    let client = websocket::ClientBuilder::new("ws://...")?.connect_insecure()?;
    Ok(Session { client })
} 

Source

vs if this was implemented -

use anyhow::Result;
use websocket;

fn main() -> Result<()> {
    let session = Session::new()?;
    Ok(())
}

struct Session {
    client: websocket::sync::Client<impl websocket::sync::Stream>
}

impl Session {
	fn new() -> Result<Self> {
	    let client = websocket::ClientBuilder::new("ws://...")?.connect_insecure()?;
	    Ok(Session { client })
	}
}

Is there a tracking issue for named existential types? The original tracking issue (#44685) was closed as a duplicate of #34511, which was closed in favor of this issue, but I don't see named existential types mentioned anywhere here...

Is there a tracking issue for named existential types?

@ibraheemdev #63063
https://rust-lang.github.io/rfcs/2515-type_alias_impl_trait.html