I just realized, that Self
can not have generics (Self<T>
), is this a feature or just something, that will be implemented in the future?
struct Example<T> {}
impl<T> Example<T> {
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Self<U>;
}
I just realized, that Self
can not have generics (Self<T>
), is this a feature or just something, that will be implemented in the future?
struct Example<T> {}
impl<T> Example<T> {
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Self<U>;
}
AFAIK this is intentional: Self
is not Example
(the generic type), but Example<T>
(the concrete type).
Think of it like this: you're implementing the method on the type Example<T>
, not on Example
. Note that you can totally have an impl Example<i32>
to add methods on only the Example<i32>
type, and in that case the type you're implementing on is Example<i32>
, so that's what Self
is.
If you need to return some other type such as Example<U>
, then type that.
I'd say there's several valid ways to look at this issue. As you mentioned, on a type level, Example<i32>
and Example<i64>
are completely different, because generics are just a template and one can imagine, that the compiler creates a type Example__i32
and Example__i64
for those two arguments provided to the Example<T>
template. One could argue, that Self
ought to reflect only full types, which comes with a lot of conveniences for generic types, as you don't have to repeatedly type the generic parameters. It follows the DRY principle and I can't complain about it.
However, on a more abstract level, which the templates themselves are on, partial types do exist and we deal with them on a regular basis. They exist for the same DRY principles Self
exists. In that regard, one could argue, that there ought to be a way to refer to the partial type Example
in a DRY manner, thus the legitimate question about Self
referring to the partial type.
However, it is in conflict with the first definition of Self
, so we have to pick one. Do we really, though? I don't see a reason to reject the request, just because someone had made a decision in the past about how Self
should work and assume, that everything that has been done is perfect and shall never be touched, again. That conservative approach just leads to stagnation and by that standard, Rust wouldn't even exist in the first place. There is always something, that can be improved, optimized, simplified and sometimes novel solutions appear for problems, that thought be "perfectly" optimized.
Personally, I could imagine that Self
is just a shortcut for Self<T>
and Self<U>
could work just fine. If we're already dealing with templates anyway, why would I have be so concrete about Example__i32
, when all I'm seeing in the code is Example<T>
? Self
could be handled just like any other template.
In the end, all that matters is how much work someone is willing to put into their ideas. Finding people with shared interests is always a good start, but it all boils down to someone having to implement the requested feature. If no one is willing to do that, even the best ideas are worth nothing. Therefore, you either do it yourself or you better be good at marketing your idea, to find someone else who does it for you.
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.