4 ms·
I think traits are really confusing (dispatch by input AND output type), there's also trait inheritance, trait bounds, casting things to traits; add type infere
by iopq 12y ago
I think traits are really confusing (dispatch by input AND output type), there's also trait inheritance, trait bounds, casting things to traits; add type inference to that, lifetime parameters and generics. You get things like
struct Foo<'a, P>
where P: std::ops::Neg + 'a,
<P as std::ops::Neg>::Output: 'a {
foo: &'a Bar<P>,
}
after further research this makes sense, of course, but looks like non-sense to anyone just trying to learn the language
- dbaupp 12y agoHm, maybe I just "know too much", but it seems to me that most of the parts of the type system are relatively independent: there's not too many weird interactions between the various parts, and many systems are complex because of the surprising interactions. In any case, half the "complexity" in the example you give is the noise of using the fully-qualified std::ops::Neg path in the bounds, rather than importing it and just writing `Neg`. :)
- baq 12y agoTBH whenever I see type names being added to each other, my brain kind of shuts down the relevant lobes. Granted, I'm barely initiated to Rust, but... it just looks confusing. (It doesn't help that it's not actually type names, but a type name and a lifetime...)
- pcwalton 12y agoI've seen this example several times now, and I never got why it was so bad: it's mostly an objection to the namespace qualification syntax if anything. It would actually be written: use std::ops::Neg; struct Foo<'a,P> where P: Neg + 'a, <P::Neg>::Output: 'a { foo: &'a Bar<P>, } And with further proposed improvements it would be: use std::ops::Neg; struct Foo<'a,P> where P: Neg + 'a, P::Output: 'a { foo: &'a Bar<P>, } Not bad. It's saying "I have a generic structure over a type parameter P tied to a lifetime 'a, and P must overload the unary minus operator".
- iopq 12y agoI think namespace qualification syntax and trait bounds make it more confusing `<P::Neg>::Output: 'a` gives me eye cancer and my intuition is if `P: Neg + 'a` then `P::Output: 'a` is implied (why would it not have that bound if P does?) the Neg trait's Output IS Self (as Neg)! Why is the bound not transitive?
- pcwalton 12y ago> `<P::Neg>::Output: 'a` gives me eye cancer and my intuition is if `P: Neg + 'a` then `P::Output: 'a` is implied (why would it not have that bound if P does?) What if the output of the unary minus method was say, a constant 'static? This is a reasonable thing for a function to want to do in general. (Probably not for Neg in particular, but obviously we don't want to add special cases in the inference for specific traits.) The function needs to know about it because you can do many more things with a 'static than a 'a (as 'static references can never become dangling).
- iopq 12y agoBut it's not, the Output is Self not Self + 'static
- pcwalton 12y agoI think you're misunderstanding what Self means in the definition of Neg. The Self is only there so that it is clear which type's "Output" is being referred to. It doesn't establish any type/trait/lifetime relationship between the type of the receiver and the output type. It would be perfectly possible to implement Neg with a 'static output lifetime.
- iopq 12y agoYeah, I got it, people on IRC helped me understand that it's not casting it as `Neg`, it's casting the type as `Neg` for namespacing purposes