-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Make return type of the Fn
traits an associated type
#20871
Comments
Nominating because we ought to settle this. Also, it's observable as the @alexcrichton example shows (though it's a backwards compat change, I believe). |
(Also, this seems like a small enough detail that I don't think it merits a full RFC.) |
+1. I think making the return type an associated type could allow for a generic implementation of currying too. |
While I'm in the "unrestricted overloading" camp for unboxed closures, I'm willing to support this if it enables more patterns like Question: would the sugar for unboxed closure bounds change? |
If you view traits with associated types as something like type level functions then making the return type of The // note: haven't tried compiling this
trait TyFn<In> { type Out; }
enum Identity<A> {}
impl<A> TyFn<A> for Identity<A> { type Out = A; }
enum Dup<A> {}
impl<A> TyFn<A> for Dup<A> { type Out = (A, A); }
trait IsComposite { type Fst; type Snd; }
impl<A, B> IsComposite for (A, B) { type Fst = A; type Snd = B; }
enum Swap<A: IsComposite> {}
impl<A: IsComposite> TyFn<A> for Swap<A> { type Out = (<A as IsComposite>::Snd, <A as IsComposite>::Fst); }
struct Helper<X, TF: TyFn<X>>;
impl<A, TF: TyFn<A>> Fn(A) for Helper<A, TF> {
type R = <TF as TyFn<A>>::Out;
…
} |
I'm convinced. |
I've got this ~95% implemented. |
See this comment for one interesting ramification / interaction. |
I've decided to open an RFC for this. Better to err on the side of more RFCs, I figure. |
I think that the argument types cannot be an associated type, but the return type of the
Fn
traits can and ought to be.Why make the return type associated?
It seems right: I don't think I want the ability to have functions overloaded purely on return type. A similar argument was gracefully made by @aturon regarding binary operators recently.
But also, it would make an impl like example (from @alexcrichton) legal:
Right now this is illegal because the type
R
is unconstrained. This is kind of counter-intuitive.Why not make the argument types associated?
The reason that the argument types cannot be associated is because of HRTB. Imagine we have a constraint like
F : Fn(&i32) -> &i32
. Now, if bothA
andR
were associated types, we'd have to be able to evaluate independent projections likeF::A
andF::R
but ensure that we got consistent lifetimes in both cases -- unfortunately, we can't do that, because there is nothing linking the lifetimes together. Put another way, ifA
andR
were associated types, thenF : Fn(&i32) -> &i32
would be sugared into three predicates internally:F : Fn
for<'a> <F as Fn>::A == &'a i32
for<'b> <F as Fn>::R == &'b i32
Note that the connection between A and R has been lost. (While implementing associated types, I spent a while trying to make this work out, and it really...just doesn't.)
On the other hand, if we convert just the return type to be an associated type, the example works just fine. We desugar the
F : Fn(&i32) -> &i32
example into:for<'a> F : Fn<(&'a i32,)>
for<'a> <F as Fn<(&'a i32,)>>::R == &'a i32
Another reason not to make the argument types associated is that it permits more overloading. For example, the "identity" function works (hat tip: @eddyb):
cc @aturon @huonw
The text was updated successfully, but these errors were encountered: