{"action":"created","comment":{"url":"https://api.github.com/repos/rust-lang/rfcs/pulls/comments/41094213","id":41094213,"diff_hunk":"@@ -0,0 +1,348 @@\n+- Feature Name: function_output_type_parameters\n+- Start Date: 2015-10-02\n+- RFC PR: (leave this empty)\n+- Rust Issue: (leave this empty)\n+\n+# Summary\n+\n+Enable monomorphized return types of a function that are only abstractly defined by an trait interface by introducing a new set of \"output\" generic parameters that can be defined for a function, and extending trait bounds with the concept of \"conditional\" bounds.\n+\n+# Motivation\n+\n+For the issue this tries to solve, see\n+http://aturon.github.io/blog/2015/09/28/impl-trait/ and\n+https://github.com/rust-lang/rfcs/pull/105.\n+\n+For the motivation of this proposal, see discussion at\n+https://www.reddit.com/r/rust/comments/3mrsvx/resurrecting_impl_trait_aaron_turon/.\n+\n+The goal of this variation around abstract return types\n+is to be more general, flexible and ergonomic than the discussed options,\n+while still being a system to define fully abstract types with less\n+effort than defining newtypes.\n+\n+The proposed features should also be maximally consistent with\n+other parts of the language.\n+\n+Non goals are to introduce global return type inference in any way, including\n+leakage of OIBITs.\n+\n+# Detailed design\n+\n+Introduce these new features in the language:\n+\n+## Abstract type aliases\n+\n+Introduce a new form of type aliases that are abstract, only defined\n+in terms of trait bounds:\n+\n+```rust\n+abstract type Foo: Clone = ();\n+```\n+\n+It is legal to \"coerce\" to and from the underlying type in the\n+same privacy scope the abstract type is define in:\n+\n+```rust\n+mod x {\n+    pub abstract type Foo: Clone = ();\n+\n+    pub fn new_foo() -> Foo { () } // OK\n+}\n+let a: x::Foo = x::new_foo();      // OK\n+let b: x::Foo = a.clone();         // OK\n+let c: x::Foo = ();                // ERR\n+```\n+\n+Semantically, they should behave just like existing generic type parameters\n+with bounds do. That is to say, the language should not expose\n+any information about the type not defined by its bounds:\n+\n+```rust\n+\n+mod foo {\n+    abstract type X: Clone = ();\n+}\n+\n+fn bar<T: Clone>(a: T, b: foo::X) {\n+    // T and foo::X don't differ in any way here.\n+}\n+\n+```\n+\n+Internally, the compiler would have full knowledge about the actual type,\n+it just can't be named nor be accessed by the user because its hidden\n+behind a privacy boundary.\n+\n+Abstract type aliases can be both standalone items and associated items.\n+\n+Interestingly, at the moment it is actually legal to define a regular\n+type alias with trait bounds as referring to an private type:\n+\n+```rust\n+// compiles today (2015-10-02):\n+mod foo {\n+    pub type Bar where Bar: Clone = Baz;\n+    struct Baz;\n+}\n+let _: foo::Bar;\n+```\n+\n+In the current form, this just seems like a number of bugs caused by the\n+compiler not checking certain things.\n+\n+One alternative option here would be to change the semantic of existing type aliases\n+to that of the proposed abstract type aliases if they refer to private types.\n+\n+The benefit would be that there would be one additional feature less in the\n+language to know about. The disadvantage would be that it prevents\n+hiding the actual type if the type in question is public.\n+\n+## Output type parameters on functions\n+\n+Add a new set of generic parameters to function items.\n+The exact syntax is up to debate, this RFC will put them as a new `<>`\n+delimited list after the `()`:\n+\n+```rust\n+fn foo<T, U: A>()<V, W: B> -> X<V, W> where T: C, V: D { ... }\n+```\n+\n+The identifiers introduced like this would\n+\n+- define `abstract type` associated items on the concrete function item.\n+- be required to appear in the return type itself.\n+- be defined by type inference on the inside of the function body.\n+- would have their underlying type be private to the function body.\n+- would have their trait bounds defined the same way as for the regular\n+  input type parameters; either as `<T: X>` bounds or as part of\n+  the `where` clauses.\n+\n+```rust\n+fn foo()<T: Clone> -> T where T: Mul { 42 }\n+\n+let a = foo();     // OK\n+let b = a.clone(); // OK\n+let c = a + b;     // ERR, foo::T not known to be Add\n+let d = a * b;     // OK\n+let e = a * b;     // ERR, a and b moved, caused by foo::T not known to be Copy\n+\n+let x: foo::T = foo() // OK\n+let y: foo::T = 0     // ERR, foo::T not known to be an integer\n+\n+```\n+\n+This feature would interact with other function-related items in the same way\n+as generics already do:\n+\n+- Works for standalone functions, associated functions or methods.\n+- Not definable for closure literals, since they use concrete, inferred types.\n+- The `Output` associated type of closure traits\n+  for such a concrete function item would be simply defined in terms of the\n+  abstract output types of the function item itself:\n+\n+```rust\n+fn foo()<T: Clone> -> T where T: Mul { 42 }\n+// from compiler generated:\n+impl Fn<()> for foo {\n+    type Output = foo::T;\n+    // ...\n+}\n+\n+let x: foo::T = foo();\n+let y: foo::Output = x;        // OK\n+let z: &Fn() -> foo::T = &foo; // OK (but not very useful)\n+\n+```\n+\n+## Conditional bounds\n+\n+Extend `where` bounds with the concept of \"conditional bounds\":\n+\n+```rust\n+T: Foo if U: Bar\n+```\n+\n+Semantically, they express that the bound on the lhs of `if` is only\n+fulfilled if the bound on the rhs is.\n+\n+They can appear in any location where `where` clauses are legal,\n+including in trait definitions and abstract return types:\n+\n+```rust\n+trait Foo where Self: Add if Self: Clone { }\n+\n+fn foo<T>(t: T)<U> -> U\n+    where U: Clone if T: Clone,\n+          U: Foo,\n+{ t }\n+\n+impl Foo for i32 { }    // OK\n+let x = foo::<i32>(42); // OK\n+let y = x.clone();      // OK\n+let z = x + y;          // OK\n+let e = x * y;          // ERR, foo<i32>::U not known to be Mul\n+\n+struct X;\n+impl Foo for X { }   // OK\n+let a = foo::<X>(X); // OK\n+let b = a.clone();   // ERR, foo<X>::U is not Clone because X is not Clone\n+let c = a + b;       // ERR, foo<X>::U is not Add because foo<X>::U is not Clone\n+\n+#[derive(Clone)]\n+struct Y;\n+impl Foo for Y { }   // ERR, Y needs to implement Add if it implements Clone.\n+\n+```\n+\n+The bound needs to apply if the condition is met. Eg, for the example above:\n+\n+- If a type implements `Clone` but not `Add`,\n+  implementing `Foo` for it is an type error.\n+- If a type does not implement `Clone`, then it does not matter\n+  if the type implements `Add` or not, but a `Foo` bound will not know\n+  about `Self: Add`.\n+\n+## Sugar for defining generic type parameters\n+\n+A problem with the existing generic syntax is\n+that its often more verbose than the non-generic version of the API. Compare:\n+\n+```rust\n+fn take_iter<I: Iterator>(i: &mut I) { ... }\n+fn take_iter(i: &mut Iterator) { ... }\n+```\n+\n+Adding additional output type parameters to functions will only increase this\n+issue.\n+\n+This proposes two incremental syntax sugars for shrinking down the size of\n+generic declarations:\n+\n+1. If a generic type parameter only appears in one location in a function\n+   signature, it may be declared directly inline with the syntax\n+   `type IDENT[: BOUNDS]`.\n+   Example:\n+   ```rust","path":"text/0000-function_output_type_parameters.md","position":226,"original_position":226,"commit_id":"18920e317949771d171eb7ddb86574d9bfb9ad8b","original_commit_id":"18920e317949771d171eb7ddb86574d9bfb9ad8b","user":{"login":"mitchmindtree","id":4587373,"avatar_url":"https://avatars.githubusercontent.com/u/4587373?v=3","gravatar_id":"","url":"https://api.github.com/users/mitchmindtree","html_url":"https://github.com/mitchmindtree","followers_url":"https://api.github.com/users/mitchmindtree/followers","following_url":"https://api.github.com/users/mitchmindtree/following{/other_user}","gists_url":"https://api.github.com/users/mitchmindtree/gists{/gist_id}","starred_url":"https://api.github.com/users/mitchmindtree/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mitchmindtree/subscriptions","organizations_url":"https://api.github.com/users/mitchmindtree/orgs","repos_url":"https://api.github.com/users/mitchmindtree/repos","events_url":"https://api.github.com/users/mitchmindtree/events{/privacy}","received_events_url":"https://api.github.com/users/mitchmindtree/received_events","type":"User","site_admin":false},"body":"This code block (as well as the one in example 2) is rendering strangely, maybe add a new line and remove the space before the ticks?","created_at":"2015-10-04T03:52:22Z","updated_at":"2015-10-04T03:52:22Z","html_url":"https://github.com/rust-lang/rfcs/pull/1305#discussion_r41094213","pull_request_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/1305","_links":{"self":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/comments/41094213"},"html":{"href":"https://github.com/rust-lang/rfcs/pull/1305#discussion_r41094213"},"pull_request":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/1305"}}},"pull_request":{"url":"https://api.github.com/repos/rust-lang/rfcs/pulls/1305","id":46710720,"html_url":"https://github.com/rust-lang/rfcs/pull/1305","diff_url":"https://github.com/rust-lang/rfcs/pull/1305.diff","patch_url":"https://github.com/rust-lang/rfcs/pull/1305.patch","issue_url":"https://api.github.com/repos/rust-lang/rfcs/issues/1305","number":1305,"state":"open","locked":false,"title":"Abstract output type parameters","user":{"login":"Kimundi","id":2903206,"avatar_url":"https://avatars.githubusercontent.com/u/2903206?v=3","gravatar_id":"","url":"https://api.github.com/users/Kimundi","html_url":"https://github.com/Kimundi","followers_url":"https://api.github.com/users/Kimundi/followers","following_url":"https://api.github.com/users/Kimundi/following{/other_user}","gists_url":"https://api.github.com/users/Kimundi/gists{/gist_id}","starred_url":"https://api.github.com/users/Kimundi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Kimundi/subscriptions","organizations_url":"https://api.github.com/users/Kimundi/orgs","repos_url":"https://api.github.com/users/Kimundi/repos","events_url":"https://api.github.com/users/Kimundi/events{/privacy}","received_events_url":"https://api.github.com/users/Kimundi/received_events","type":"User","site_admin":false},"body":"Enable monomorphized return types of a function that are only abstractly defined by an trait interface by introducing a new set of \"output\" generic parameters that can be defined for a function, and extending trait bounds with the concept of \"conditional\" bounds.\r\n\r\n[Rendered](https://github.com/Kimundi/rfcs/blob/function_output_type_parameters/text/0000-function_output_type_parameters.md)","created_at":"2015-10-03T18:42:45Z","updated_at":"2015-10-04T03:52:22Z","closed_at":null,"merged_at":null,"merge_commit_sha":"d1be6e460418375d8a8257d5cb5036e1ee7680a8","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/1305/commits","review_comments_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/1305/comments","review_comment_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/rust-lang/rfcs/issues/1305/comments","statuses_url":"https://api.github.com/repos/rust-lang/rfcs/statuses/18920e317949771d171eb7ddb86574d9bfb9ad8b","head":{"label":"Kimundi:function_output_type_parameters","ref":"function_output_type_parameters","sha":"18920e317949771d171eb7ddb86574d9bfb9ad8b","user":{"login":"Kimundi","id":2903206,"avatar_url":"https://avatars.githubusercontent.com/u/2903206?v=3","gravatar_id":"","url":"https://api.github.com/users/Kimundi","html_url":"https://github.com/Kimundi","followers_url":"https://api.github.com/users/Kimundi/followers","following_url":"https://api.github.com/users/Kimundi/following{/other_user}","gists_url":"https://api.github.com/users/Kimundi/gists{/gist_id}","starred_url":"https://api.github.com/users/Kimundi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Kimundi/subscriptions","organizations_url":"https://api.github.com/users/Kimundi/orgs","repos_url":"https://api.github.com/users/Kimundi/repos","events_url":"https://api.github.com/users/Kimundi/events{/privacy}","received_events_url":"https://api.github.com/users/Kimundi/received_events","type":"User","site_admin":false},"repo":{"id":17668904,"name":"rfcs","full_name":"Kimundi/rfcs","owner":{"login":"Kimundi","id":2903206,"avatar_url":"https://avatars.githubusercontent.com/u/2903206?v=3","gravatar_id":"","url":"https://api.github.com/users/Kimundi","html_url":"https://github.com/Kimundi","followers_url":"https://api.github.com/users/Kimundi/followers","following_url":"https://api.github.com/users/Kimundi/following{/other_user}","gists_url":"https://api.github.com/users/Kimundi/gists{/gist_id}","starred_url":"https://api.github.com/users/Kimundi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Kimundi/subscriptions","organizations_url":"https://api.github.com/users/Kimundi/orgs","repos_url":"https://api.github.com/users/Kimundi/repos","events_url":"https://api.github.com/users/Kimundi/events{/privacy}","received_events_url":"https://api.github.com/users/Kimundi/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Kimundi/rfcs","description":"RFCs for changes to Rust","fork":true,"url":"https://api.github.com/repos/Kimundi/rfcs","forks_url":"https://api.github.com/repos/Kimundi/rfcs/forks","keys_url":"https://api.github.com/repos/Kimundi/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Kimundi/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Kimundi/rfcs/teams","hooks_url":"https://api.github.com/repos/Kimundi/rfcs/hooks","issue_events_url":"https://api.github.com/repos/Kimundi/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/Kimundi/rfcs/events","assignees_url":"https://api.github.com/repos/Kimundi/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/Kimundi/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/Kimundi/rfcs/tags","blobs_url":"https://api.github.com/repos/Kimundi/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Kimundi/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Kimundi/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/Kimundi/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Kimundi/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/Kimundi/rfcs/languages","stargazers_url":"https://api.github.com/repos/Kimundi/rfcs/stargazers","contributors_url":"https://api.github.com/repos/Kimundi/rfcs/contributors","subscribers_url":"https://api.github.com/repos/Kimundi/rfcs/subscribers","subscription_url":"https://api.github.com/repos/Kimundi/rfcs/subscription","commits_url":"https://api.github.com/repos/Kimundi/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/Kimundi/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/Kimundi/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/Kimundi/rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/Kimundi/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/Kimundi/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Kimundi/rfcs/merges","archive_url":"https://api.github.com/repos/Kimundi/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Kimundi/rfcs/downloads","issues_url":"https://api.github.com/repos/Kimundi/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/Kimundi/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/Kimundi/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/Kimundi/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Kimundi/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/Kimundi/rfcs/releases{/id}","created_at":"2014-03-12T14:02:43Z","updated_at":"2014-12-14T16:55:32Z","pushed_at":"2015-10-03T18:35:24Z","git_url":"git://github.com/Kimundi/rfcs.git","ssh_url":"git@github.com:Kimundi/rfcs.git","clone_url":"https://github.com/Kimundi/rfcs.git","svn_url":"https://github.com/Kimundi/rfcs","homepage":"","size":1281,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":1,"forks":1,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"rust-lang:master","ref":"master","sha":"8e2d3a3341da533f846f61f10335b72c9a9f4740","user":{"login":"rust-lang","id":5430905,"avatar_url":"https://avatars.githubusercontent.com/u/5430905?v=3","gravatar_id":"","url":"https://api.github.com/users/rust-lang","html_url":"https://github.com/rust-lang","followers_url":"https://api.github.com/users/rust-lang/followers","following_url":"https://api.github.com/users/rust-lang/following{/other_user}","gists_url":"https://api.github.com/users/rust-lang/gists{/gist_id}","starred_url":"https://api.github.com/users/rust-lang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rust-lang/subscriptions","organizations_url":"https://api.github.com/users/rust-lang/orgs","repos_url":"https://api.github.com/users/rust-lang/repos","events_url":"https://api.github.com/users/rust-lang/events{/privacy}","received_events_url":"https://api.github.com/users/rust-lang/received_events","type":"Organization","site_admin":false},"repo":{"id":17527989,"name":"rfcs","full_name":"rust-lang/rfcs","owner":{"login":"rust-lang","id":5430905,"avatar_url":"https://avatars.githubusercontent.com/u/5430905?v=3","gravatar_id":"","url":"https://api.github.com/users/rust-lang","html_url":"https://github.com/rust-lang","followers_url":"https://api.github.com/users/rust-lang/followers","following_url":"https://api.github.com/users/rust-lang/following{/other_user}","gists_url":"https://api.github.com/users/rust-lang/gists{/gist_id}","starred_url":"https://api.github.com/users/rust-lang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rust-lang/subscriptions","organizations_url":"https://api.github.com/users/rust-lang/orgs","repos_url":"https://api.github.com/users/rust-lang/repos","events_url":"https://api.github.com/users/rust-lang/events{/privacy}","received_events_url":"https://api.github.com/users/rust-lang/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/rust-lang/rfcs","description":"RFCs for changes to Rust","fork":false,"url":"https://api.github.com/repos/rust-lang/rfcs","forks_url":"https://api.github.com/repos/rust-lang/rfcs/forks","keys_url":"https://api.github.com/repos/rust-lang/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rust-lang/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rust-lang/rfcs/teams","hooks_url":"https://api.github.com/repos/rust-lang/rfcs/hooks","issue_events_url":"https://api.github.com/repos/rust-lang/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/rust-lang/rfcs/events","assignees_url":"https://api.github.com/repos/rust-lang/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/rust-lang/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/rust-lang/rfcs/tags","blobs_url":"https://api.github.com/repos/rust-lang/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rust-lang/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rust-lang/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/rust-lang/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rust-lang/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/rust-lang/rfcs/languages","stargazers_url":"https://api.github.com/repos/rust-lang/rfcs/stargazers","contributors_url":"https://api.github.com/repos/rust-lang/rfcs/contributors","subscribers_url":"https://api.github.com/repos/rust-lang/rfcs/subscribers","subscription_url":"https://api.github.com/repos/rust-lang/rfcs/subscription","commits_url":"https://api.github.com/repos/rust-lang/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/rust-lang/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/rust-lang/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/rust-lang/rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/rust-lang/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/rust-lang/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rust-lang/rfcs/merges","archive_url":"https://api.github.com/repos/rust-lang/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rust-lang/rfcs/downloads","issues_url":"https://api.github.com/repos/rust-lang/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/rust-lang/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/rust-lang/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/rust-lang/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rust-lang/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/rust-lang/rfcs/releases{/id}","created_at":"2014-03-07T21:29:00Z","updated_at":"2015-10-03T23:50:19Z","pushed_at":"2015-10-03T18:42:45Z","git_url":"git://github.com/rust-lang/rfcs.git","ssh_url":"git@github.com:rust-lang/rfcs.git","clone_url":"https://github.com/rust-lang/rfcs.git","svn_url":"https://github.com/rust-lang/rfcs","homepage":"","size":11685,"stargazers_count":469,"watchers_count":469,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":235,"mirror_url":null,"open_issues_count":565,"forks":235,"open_issues":565,"watchers":469,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/1305"},"html":{"href":"https://github.com/rust-lang/rfcs/pull/1305"},"issue":{"href":"https://api.github.com/repos/rust-lang/rfcs/issues/1305"},"comments":{"href":"https://api.github.com/repos/rust-lang/rfcs/issues/1305/comments"},"review_comments":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/1305/comments"},"review_comment":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/1305/commits"},"statuses":{"href":"https://api.github.com/repos/rust-lang/rfcs/statuses/18920e317949771d171eb7ddb86574d9bfb9ad8b"}}}}