rust-lang / rust

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

Tracking issue for trait aliases #41517

Open withoutboats opened 7 years ago

withoutboats commented 7 years ago

This is a tracking issue for trait aliases (rust-lang/rfcs#1733).

TODO:

Unresolved questions:

benjaminmordaunt commented 2 years ago

Perhaps I'm misunderstanding this. I want trait aliases to allow something like this, to allow giving more meaningful names to specialised traits:

pub trait Mapper<Tr, Tw> {
    fn read(&self, addr: u16) -> Tr;
    fn write(&mut self, addr: u16, data: u8) -> Result<Tw, String>;
}

pub trait CPUMapper = Mapper<u8, ()>;
pub trait PPUMapper = Mapper<u16, u16>;

impl CPUMapper for CPUMapper000 { /* should == impl Mapper<u8, ()> for CPUMapper000 {
    /* NOT ALLOWED! */
}

But rustc complains that it's looking for a trait, but finding a trait alias... isn't that the point? I understand this might become an issue when traits are composed together, and you try to impl a set of traits at once. But can't there be a check to see if we're aliasing only a single trait, to allow its use in an impl Trait for T block?

varkor commented 2 years ago

@benjaminmordaunt: this is one of the issues with the current design of the language feature. "Trait aliases" are not really trait aliases: they are bounds aliases (https://github.com/rust-lang/rust/issues/41517#issuecomment-479226997). I feel this is strongly misleading (as evidenced by your comment).

clarfonthey commented 2 years ago

Here's a silly idea that (kind of) abuses the impl Trait syntax:

impl Alias = impl One + Two;

This would be a bounds alias, and it essentially clarifies that using impl Alias is the same as using impl One + Two, but doesn't make any specific guarantees about it being a trait in its own right.

For creating proper trait aliases, we could do something like:

impl trait Alias = impl One + Two;

This would essentially say: implement the trait Alias for everything that implements One + Two.

reuvenpo commented 2 years ago

@clarfonthey You can do the latter in stable rust with something like this:

pub trait Alias: One + Two {}

impl<T> Alias for T where T: One + Two {}

It's a little awkward to write because it has a bit of duplication, but it's been working well for me in cases where i needed to alias a bound of the sum of ~10 traits together.

freemanliu commented 2 years ago

@reuvenpo, Not sure if this trick works with Fn, which is implmented by closure. For an alias below: pub trait MyF: Fn(i32) -> i32

how to implement it for a closure? Like fn createMyF() -> MyF { |i| -> 2*i }

UPDATE: switched to nightly rust and trait alias works!

reuvenpo commented 2 years ago

@freemanliu This works in stable: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=a41bef6b7ea84bad47461e3834ae7bcc

clarfonthey commented 2 years ago

@clarfonthey You can do the latter in stable rust with something like this:

pub trait Alias: One + Two {}

impl<T> Alias for T where T: One + Two {}

It's a little awkward to write because it has a bit of duplication, but it's been working well for me in cases where i needed to alias a bound of the sum of ~10 traits together.

You are correct, but the suggestion would be to simply make it sugar for that, if such a feature were desired. Right now, the main intent of trait aliases is to act as bounds aliases, but for those who want proper trait aliases, this could be an alternative syntax.

matzipan commented 1 year ago

Trying this unstable feature in 1.66.0 nightly.

For this type:

trait FactoryFunctionType = Fn(u32, &glib::Object) -> gtk::Widget;

It can't seem to be able to infer the type of ::Output type for this function type. It resolves to <dyn FactoryFunctionType as FnOnce<(u32, &Object)>>::Output which seems to be missing the -> gtk::Widget return type.

jonaspleyer commented 1 year ago

Please have a look at #106238 which I just filed.

Kixunil commented 1 year ago

I found it'd be useful to allow impls of certain trait aliases. Consider this code:

Crate A:

pub trait Encode<Strategy> {
    type Encoder: Encoder;

    fn encode(&self) -> Self::Encoder;
}

Crate B:

// Whole crate uses this strategy, so it's repeated everywhere.
pub enum ThisCrateStrategy {}

// To implement the trait in different modules of the crate each must import both `Encode` and `ThisCrateStrategy`.
impl Encode<ThisCrateStrategy> for u32 {
    type Encoder = U32Encoder;

    fn encode(&self) -> Self::Encoder {
        U32Encoder::new(*self)
    }
}

Instead it should be possible to allow this:

pub enum ThisCrateStrategy {}

pub trait ThisCrateEncode = Encode<ThisCrateStrategy>;

impl ThisCrateEncode for u32 {
    type Encoder = U32Encoder;

    fn encode(&self) -> Self::Encoder {
        U32Encoder::new(*self)
    }
}
Jules-Bertholet commented 1 year ago

I found it'd be useful to allow impls of certain trait aliases.

I have an open RFC for this: https://github.com/rust-lang/rfcs/pull/3437

ms-ati commented 4 months ago

Q: Does trait aliases have any projected timeframe to reach stable?

nikomatsakis commented 4 months ago

Not at present but at least some subset of them would be useful for async code, so I'm hoping to get that done this year.

ilonachan commented 4 months ago

Just to make sure you know (bc I don't actually know GitHub very well) I found a (likely) bug and opened https://github.com/rust-lang/rust/issues/127725 for it.