Open withoutboats opened 7 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?
@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).
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
.
@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.
@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!
@freemanliu This works in stable: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=a41bef6b7ea84bad47461e3834ae7bcc
@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.
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.
Please have a look at #106238 which I just filed.
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)
}
}
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
Q: Does trait aliases have any projected timeframe to reach stable?
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.
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.
This is a tracking issue for trait aliases (rust-lang/rfcs#1733).
TODO:
unexpected definition: TraitAlias
INCOHERENT_AUTO_TRAIT_OBJECTS
future-compatibility warning (superseded by https://github.com/rust-lang/rust/pull/56481)Unresolved questions:
?Sized
bounds in trait objects, ban them "deeply" (through trait alias expansion), or permit them everywhere with no effect?