{"action":"created","issue":{"url":"https://api.github.com/repos/rust-lang/rfcs/issues/376","labels_url":"https://api.github.com/repos/rust-lang/rfcs/issues/376/labels{/name}","comments_url":"https://api.github.com/repos/rust-lang/rfcs/issues/376/comments","events_url":"https://api.github.com/repos/rust-lang/rfcs/issues/376/events","html_url":"https://github.com/rust-lang/rfcs/issues/376","id":45310679,"number":376,"title":"Draft RFC: variadic generics","user":{"login":"rust-highfive","id":7378925,"avatar_url":"https://avatars.githubusercontent.com/u/7378925?v=3","gravatar_id":"","url":"https://api.github.com/users/rust-highfive","html_url":"https://github.com/rust-highfive","followers_url":"https://api.github.com/users/rust-highfive/followers","following_url":"https://api.github.com/users/rust-highfive/following{/other_user}","gists_url":"https://api.github.com/users/rust-highfive/gists{/gist_id}","starred_url":"https://api.github.com/users/rust-highfive/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rust-highfive/subscriptions","organizations_url":"https://api.github.com/users/rust-highfive/orgs","repos_url":"https://api.github.com/users/rust-highfive/repos","events_url":"https://api.github.com/users/rust-highfive/events{/privacy}","received_events_url":"https://api.github.com/users/rust-highfive/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":13,"created_at":"2014-10-08T23:34:41Z","updated_at":"2015-03-04T01:24:14Z","closed_at":null,"body":"<a href=\"https://github.com/eddyb\"><img src=\"https://avatars.githubusercontent.com/u/77424?v=2\" align=\"left\" width=\"96\" height=\"96\" hspace=\"10\"></img></a> **Issue by [eddyb](https://github.com/eddyb)**\n_Monday Oct 28, 2013 at 17:39 GMT_\n\n_For earlier discussion, see https://github.com/rust-lang/rust/issues/10124_\n\n_This issue was labelled with: B-RFC in the Rust repository_\n\n----\n\n## The Problem\r\n* [fn types need a reform](http://smallcultfollowing.com/babysteps/blog/2013/10/10/fn-types-in-rust/), and being able to define a trait with a variable number of type parameters would help\r\n* working with functions which have a variable number of arguments is impossible right now (e.g. a generic `bind` method, `f.bind(a, b)(c) == f(a, b, c)`) and defining such functions may only be done (in a limited fashion) with macros\r\n* tuples also have similar restrictions right now, there is no way to define a function which takes any tuple and returns the first element, for example\r\n\r\n## The Solution: Part One\r\nC++11 sets a decent precedent, with its variadic templates, which can be used to define type-safe variadic functions, among other things.\r\nI propose a similar syntax, a trailing `..T` in generic formal type parameters:\r\n```rust\r\ntype Tuple<..T> = (..T); // the parens here are the same as the ones around a tuple.\r\n// use => expansion\r\nTuple<> => ()\r\nTuple<int> => (int,)\r\nTuple<A, B, C> => (A, B, C)\r\n```\r\nThe simple example above only uses `..T`, but not `T` itself.\r\nThe question which arises is this: what is `T`? C++11 has a special case for variadic parameter packs, but we can do better.\r\nWe have tuples. We can use them to store the actual variadic generic type parameters:\r\n```rust\r\n// Completely equivalent definition:\r\ntype Tuple<..T> = T;\r\n// Detailed expansion of (..T) from above:\r\nTuple<> => (..()) => ()\r\nTuple<int> => (..(int,)) => (int,)\r\nTuple<A, B, C> => (..(A, B, C)) => (A, B, C)\r\n```\r\n\r\n## The Solution: Part Two\r\nNow that we know the answer is \"tuples\", everything else is about extending them.\r\nThe prefix `..` operator would expand a tuple type:\r\n```rust\r\n// in another tuple type:\r\ntype AppendTuple<T, U> = (..T, U);\r\ntype PrependTuple<T, U> = (U, ..T);\r\nAppendTuple<PrependTuple<Tuple<B>, A>, C> => (A, B, C)\r\n// in a fn type's parameter list:\r\ntype VoidFn<..Args> = fn(..Args);\r\nVoidFn<A, B, C> => fn(A, B, C);\r\n// in a variadic generic parameter list:\r\nTuple<..(A, B, C), ..(D, E, F)> => (A, B, C, D, E, F)\r\n```\r\nThen we can do the same thing with values:\r\n```rust\r\n// in another tuple:\r\n(..(true, false), ..(1, \"foo\"), \"bar\") => (true, false, 1, \"foo\", \"bar\")\r\n// in a function call:\r\nf(..(a, b), ..(c, d, e), f) => f(a, b, c, d, e, f)\r\n```\r\nThere's only one piece missing: we're still not able to define a function which takes a variable number of arguments.\r\nFor this, I propose `..x: T` (where T is a tuple type) in a pattern, which can be used to \"capture\" multiple arguments  when used in fn formal arguments:\r\n```rust\r\n// Destructure a tuple.\r\nlet (head, ..tail) = foo;\r\n// This function has the type fn(int, A, B, C), and can be called as such:\r\nfn bar(_: int, ..x: (A, B, C)) -> R {...}\r\n```\r\nA type bound for `..T` (i.e. `impl<..T: Trait>`) could mean that the tuple `T` has to satisfy the bound (or each type in `T`, but that's generally less useful).\r\n## Examples:\r\n```rust\r\n// The highly anticipated Fn trait.\r\ntrait Fn<Ret, ..Args> {\r\n    fn call(self, .._: Args) -> Ret;\r\n}\r\nimpl Fn<Ret, ..Args> for fn(..Args) -> Ret {\r\n    fn call(self, ..args: Args) -> Ret {\r\n        self(..args)\r\n    }\r\n}\r\nimpl Fn<Ret, ..Args> for |..Args| -> Ret {\r\n    fn call(self, ..args: Args) -> Ret {\r\n        self(..args)\r\n    }\r\n}\r\n\r\n// Cloning tuples (all cons-list-like algorithms can be implemented this way).\r\nimpl<Head, ..Tail: Clone> Clone for (Head, ..Tail) {\r\n    fn clone(&self @ &(ref head, ..ref tail)) -> (Head, ..Tail) {\r\n        (head.clone(), ..tail.clone())\r\n    }\r\n}\r\nimpl Clone for () {\r\n    fn clone(&self) -> () {\r\n        ()\r\n    }\r\n}\r\n\r\n// Restricting all types in a variadic tuple to one type.\r\ntrait ArrayLikeTuple<T> {\r\n    fn len() -> uint;\r\n}\r\nimpl<T> ArrayLikeTuple<T> for () {\r\n    fn len() -> uint {0}\r\n}\r\nimpl<T, ..Tail: ArrayLikeTuple<T>> ArrayLikeTuple<T> for (T, ..Tail) {\r\n    fn len() -> uint {\r\n        1 + Tail::len()\r\n    }\r\n}\r\n\r\n// And using that trait to write variadic container constructors.\r\nimpl<T> Vec<T> {\r\n    fn new<..Args: ArrayLikeTuple<T>>(..args: Args) -> Vec<T> {\r\n        let v: Vec<T> = Vec::with_capacity(Args::len());\r\n        // Use an unsafe move_iter-like pattern to move all the args\r\n        // directly into the newly allocated vector. \r\n        // Alternatively, implement &move [T] and move_iter on that.\r\n    }\r\n}\r\n\r\n// Zipping tuples, using a `Tuple` kind and associated items.\r\ntrait TupleZip<Other>: Tuple {\r\n    type Result: Tuple;\r\n    fn zip(self, other: Other) -> Result;\r\n}\r\nimpl TupleZip<()> for () {\r\n    type Result = ();\r\n    fn zip(self, _: ()) -> () {}\r\n}\r\nimpl<A, ATail: TupleZip<BTail>, B, BTail: Tuple> TupleZip<(B, ..BTail)> for (A, ..ATail) {\r\n    type Result = ((A, B), ..ATail::Result);\r\n    fn zip(self @ (a, ..a_tail), (b, ..b_tail): (B, ..BTail)) -> Result {\r\n        ((a, b), ..a_tail.zip(b_tail))\r\n    }\r\n}\r\n```\r\n\r\n## Todo\r\n* better formal descriptions\r\n* figure out the details of pattern matching\r\n* more examples\n"},"comment":{"url":"https://api.github.com/repos/rust-lang/rfcs/issues/comments/77079279","html_url":"https://github.com/rust-lang/rfcs/issues/376#issuecomment-77079279","issue_url":"https://api.github.com/repos/rust-lang/rfcs/issues/376","id":77079279,"user":{"login":"oblitum","id":1269815,"avatar_url":"https://avatars.githubusercontent.com/u/1269815?v=3","gravatar_id":"","url":"https://api.github.com/users/oblitum","html_url":"https://github.com/oblitum","followers_url":"https://api.github.com/users/oblitum/followers","following_url":"https://api.github.com/users/oblitum/following{/other_user}","gists_url":"https://api.github.com/users/oblitum/gists{/gist_id}","starred_url":"https://api.github.com/users/oblitum/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/oblitum/subscriptions","organizations_url":"https://api.github.com/users/oblitum/orgs","repos_url":"https://api.github.com/users/oblitum/repos","events_url":"https://api.github.com/users/oblitum/events{/privacy}","received_events_url":"https://api.github.com/users/oblitum/received_events","type":"User","site_admin":false},"created_at":"2015-03-04T01:24:14Z","updated_at":"2015-03-04T01:24:14Z","body":"@gnzlbg that's C++1z actually."}}