-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Associated traits #2190
Comments
This could mix well with higher-kinded-types/#1598 (or whatever equivalent ends up getting implemented). Something like: pub trait Map<K: Self::Key, V: Self::Value> {
trait Key;
trait Value;
...
}
impl<K: Hash, V> Map<K, V> for HashMap<K, V> {
trait Key = Hash;
trait Value = Any;
...
} Ideally these would be more like 'associated type bounds'. |
The equivalent feature in GHC is called |
I'm interested in collaboration on an RFC regarding this. |
Does it make sense to support this? impl Handler for Foo {
trait Arg = 'static;
} |
@kennytm What is the use case you have in mind? It feels natural to support lifetime bounds. |
@Centril something about this trait PointerFamily {
trait Bounds;
type Pointer<T: ?Sized>;
}
struct ConstPtrFamily;
impl PointerFamily for ConstPtrFamily {
trait Bounds = Copy + Ord + Hash + UnwindSafe + 'static;
type Pointer<T: ?Sized> = *const T;
}
struct RefFamily<'a>(PhantomData<&'a ()>);
impl<'a> PointerFamily for RefFamily<'a> {
trait Bounds = Copy + Send + Sync + UnwindSafe + 'a;
type Pointer<T: ?Sized> = &'a T;
}
struct RcFamily;
impl PointerFamily for RcFamily {
trait Bounds = Clone + UnwindSafe + 'static;
type Pointer<T: ?Sized> = Rc<T>;
} |
I've started a dedicated repo for research and writing on a ConstraintKinds RFC: I'd love it if y'all would:
|
I've been working on something, and Associated traits would work really nicely with it. trait Comp {
type Props: Clone + 'static;
trait Events;
fn new(props: Self::Props) -> Self;
}
struct Label {
value: String,
}
impl Comp for Label {
type Props = LabelProps;
trait Events = LabelEvents;
fn new(props: Self::Props) -> Self {
unimplemented!()
}
}
struct LabelProps {
value: String,
}
trait LabelEvents {
}
impl LabelEvents for OnClick {
/* ... */
}
struct OnClick;
struct KeyPress;
struct Context<C: Comp> {
}
impl<C> Context<C> {
fn listen<E>(&mut self, func: impl for<'r> Fn(&'r mut Context<C>, E)) where E: C::Events {
unimplemented!()
}
}
fn create_panel() {
let ctx: &mut Context<Label> = unimplemented!();
ctx.listen::<OnClick>(|ctx, event| {
// Do something with the event
});
// Compile error.
ctx.listen::<KeyPress>(|ctx, event| {
});
} |
This feature would come in very handy. My use case would be something like the following: trait Monitor {
type Action; // Usually some kind of enum
}
trait SetLikeMonitor : Monitor {
fn mk_put() -> Self::Action; // these only exist in SetLikeMonitor!
fn mk_rm() -> Self::Action;
}
struct SillySet { ... }
// SillySet is a set-like data structure, so we constrain what kind of monitors are allowed,
// because we need the `mk_put` and `mk_rm` functions to generate the appropriate actions.
impl MyTrait for SillySet {
trait Mon: SetLikeMonitor;
fn apply<M: Self::Mon>(...) -> Self::Mon::Action {
...
M::mk_put()
}
} So (Edit: Someone on the Rust community discord came up with a workaround) |
Several days ago I figured that that would help me implement/request trait for the associated type (through a few more steps) https://stackoverflow.com/questions/71522871/rust-implement-trait-for-the-associated-type There's a pattern that allows to achieve what I wanted in Rust with the addition of generic associated types (GATs). Yet I'm still working on pinpointing the pattern. Warning: I haven't used Haskell for quite a while and I didn't work much with its kind system. |
One important application of associated traits is ability to define trait DefaultSpecializationExt {
trait Trait;
type DefaultSpecialization: Self::Trait;
} Without associated traits, the default specialization would be unbounded or there would be a whole family of traits related only intuitively.
|
I could also really use this, as I have pub trait Item { ... }
impl Item for EnvironmentItem { ... }
impl Item for PanelItem { ... }
pub struct ItemUI<I: Item, T: Send + Sync + 'static> {
...
} where I want ItemUI<PanelItem, T: PanelItemHandler> and ItemUI<EnvironmentItem, T: Any> to be enforced. I could easily do that with pub trait Item {
trait Handler;
...
}
impl Item for EnvironmentItem {
trait Handler = Any;
...
}
impl Item for PanelItem {
trait Handler = PanelItemHandler
...
}
pub struct ItemUI<I: Item, T: I::Handler + Send + Sync + 'static> {
node: Arc<Node>,
items: Mutex<FxHashMap<String, HandlerWrapper<I, T>>>,
} but other methods would require a bigger hassle, such as making multiple |
What are the next steps here? Does someone need to write a formal RFC? |
RFC 1733 added trait aliases, like:
Well, why not allow putting those in traits, by analogy with associated types looking like type aliases? For example:
Example of a function that's generic over implementations of
Handler
:Associated traits could also have supertrait bounds.
And if
impl Trait
syntax is extended to function arguments, they'd be a natural fit:(I was just writing some code where this could have come in handy.)
There's also the natural dual of allowing traits as generic parameters, just as associated types mirror regular type parameters and associated consts mirror the upcoming 'const generics'. Something like
I think this has been proposed before.
The text was updated successfully, but these errors were encountered: