{"action":"created","issue":{"url":"https://api.github.com/repos/rust-lang/rust/issues/20871","labels_url":"https://api.github.com/repos/rust-lang/rust/issues/20871/labels{/name}","comments_url":"https://api.github.com/repos/rust-lang/rust/issues/20871/comments","events_url":"https://api.github.com/repos/rust-lang/rust/issues/20871/events","html_url":"https://github.com/rust-lang/rust/issues/20871","id":53959005,"number":20871,"title":"Make return type of the `Fn` traits an associated type","user":{"login":"nikomatsakis","id":155238,"avatar_url":"https://avatars.githubusercontent.com/u/155238?v=3","gravatar_id":"","url":"https://api.github.com/users/nikomatsakis","html_url":"https://github.com/nikomatsakis","followers_url":"https://api.github.com/users/nikomatsakis/followers","following_url":"https://api.github.com/users/nikomatsakis/following{/other_user}","gists_url":"https://api.github.com/users/nikomatsakis/gists{/gist_id}","starred_url":"https://api.github.com/users/nikomatsakis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nikomatsakis/subscriptions","organizations_url":"https://api.github.com/users/nikomatsakis/orgs","repos_url":"https://api.github.com/users/nikomatsakis/repos","events_url":"https://api.github.com/users/nikomatsakis/events{/privacy}","received_events_url":"https://api.github.com/users/nikomatsakis/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/rust-lang/rust/labels/A-closures","name":"A-closures","color":"d7e102"},{"url":"https://api.github.com/repos/rust-lang/rust/labels/I-nominated","name":"I-nominated","color":"e10c02"}],"state":"open","locked":false,"assignee":{"login":"nikomatsakis","id":155238,"avatar_url":"https://avatars.githubusercontent.com/u/155238?v=3","gravatar_id":"","url":"https://api.github.com/users/nikomatsakis","html_url":"https://github.com/nikomatsakis","followers_url":"https://api.github.com/users/nikomatsakis/followers","following_url":"https://api.github.com/users/nikomatsakis/following{/other_user}","gists_url":"https://api.github.com/users/nikomatsakis/gists{/gist_id}","starred_url":"https://api.github.com/users/nikomatsakis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nikomatsakis/subscriptions","organizations_url":"https://api.github.com/users/nikomatsakis/orgs","repos_url":"https://api.github.com/users/nikomatsakis/repos","events_url":"https://api.github.com/users/nikomatsakis/events{/privacy}","received_events_url":"https://api.github.com/users/nikomatsakis/received_events","type":"User","site_admin":false},"milestone":null,"comments":8,"created_at":"2015-01-10T14:03:02Z","updated_at":"2015-01-11T00:37:43Z","closed_at":null,"body":"I think that the argument types cannot be an associated type, but the return type of the `Fn` traits can and ought to be.\r\n\r\n### Why make the return type associated?\r\n\r\nIt 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](http://discuss.rust-lang.org/t/implicit-widening-polymorphic-indexing-and-similar-ideas/1141/15?u=nikomatsakis).\r\n\r\nBut also, it would make an impl like example (from @alexcrichton) legal:\r\n\r\n```rust\r\nimpl<R,F> Foo for F : FnMut() -> R { ... }\r\n```\r\n\r\nRight now this is illegal because the type `R` is unconstrained. This is kind of counter-intuitive.\r\n\r\n### Why not make the argument types associated?\r\n\r\nThe reason that the argument types cannot be associated is because of HRTB. Imagine we have a constraint like `F : Fn(&i32) -> &i32`. Now, if both `A` and `R` were associated types, we'd have to be able to evaluate independent projections like `F::A` and `F::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, if `A` and `R` were associated types, then `F : Fn(&i32) -> &i32` would be sugared into three predicates internally:\r\n\r\n- `F : Fn`\r\n- `for<'a> <F as Fn>::A == &'a i32`\r\n- `for<'b> <F as Fn>::R == &'b i32`\r\n\r\nNote 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.)\r\n\r\nOn 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:\r\n\r\n- `for<'a> F : Fn<(&'a i32,)>`\r\n- `for<'a> <F as Fn<(&'a i32,)>>::R == &'a i32`\r\n\r\nAnother reason not to make the argument types associated is that it permits more overloading. For example, the \"identity\" function works (hat tip: @eddyb):\r\n\r\n```rust\r\nstruct Identity;\r\nimpl<A> Fn(A) for Identity {\r\n    type R = A;\r\n    fn call(&self, (arg,): (A,)) -> A {\r\n        arg\r\n    }\r\n}\r\n```\r\n\r\ncc @aturon @huonw "},"comment":{"url":"https://api.github.com/repos/rust-lang/rust/issues/comments/69478505","html_url":"https://github.com/rust-lang/rust/issues/20871#issuecomment-69478505","issue_url":"https://api.github.com/repos/rust-lang/rust/issues/20871","id":69478505,"user":{"login":"nikomatsakis","id":155238,"avatar_url":"https://avatars.githubusercontent.com/u/155238?v=3","gravatar_id":"","url":"https://api.github.com/users/nikomatsakis","html_url":"https://github.com/nikomatsakis","followers_url":"https://api.github.com/users/nikomatsakis/followers","following_url":"https://api.github.com/users/nikomatsakis/following{/other_user}","gists_url":"https://api.github.com/users/nikomatsakis/gists{/gist_id}","starred_url":"https://api.github.com/users/nikomatsakis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nikomatsakis/subscriptions","organizations_url":"https://api.github.com/users/nikomatsakis/orgs","repos_url":"https://api.github.com/users/nikomatsakis/repos","events_url":"https://api.github.com/users/nikomatsakis/events{/privacy}","received_events_url":"https://api.github.com/users/nikomatsakis/received_events","type":"User","site_admin":false},"created_at":"2015-01-11T00:37:43Z","updated_at":"2015-01-11T00:37:43Z","body":"I've got this ~95% implemented."}}