{"action":"created","comment":{"url":"https://api.github.com/repos/Centril/rfcs/pulls/comments/242389403","pull_request_review_id":185880212,"id":242389403,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDI0MjM4OTQwMw==","diff_hunk":"@@ -0,0 +1,1658 @@\n+- Feature Name: `default_field_values`\n+- Start Date: 2018-12-17\n+- RFC PR:\n+- Rust Issue:\n+\n+# Summary\n+[summary]: #summary\n+\n+Allow `struct` definitions and `enum` variants to provide default values for\n+individual fields and thereby allowing those to be omitted from initializers.\n+When deriving `Default`, the provided values will then be used. For example:\n+\n+```rust\n+#[derive(Default)]\n+struct ExprType {\n+    expr: Box<Expr>,\n+    ty: Box<Ty>\n+    attrs: Vec<Attribute> = Vec::new(),\n+}\n+```\n+\n+An attribute `#[default]` is also introduced which can be used on `enum`\n+variants thereby allowing enums to work with `#[derive(Default)]`.\n+\n+```rust\n+#[derive(Default)]\n+enum Expr {\n+    #[default]\n+    Field {\n+        base: Box<Expr>,\n+        member: Ident,\n+        attrs: Vec<Attribute> = Vec::new(),\n+    },\n+    // other variants...\n+}\n+\n+let ascribe = ExprType { expr: make_expr(), ty, .. };\n+let field = Expr::Field { base, member, .. };\n+```\n+\n+# Motivation\n+[motivation]: #motivation\n+\n+## Boilerplate reduction\n+\n+### For `struct`s\n+\n+Rust allows you to create an instance of a `struct` using the struct literal\n+syntax `Foo { bar: expr, baz: expr }`. To do so, all fields in the `struct`\n+must be assigned a value. This makes it inconvenient to create large `struct`s\n+whose fields usually receive the same values. Struct literals also cannot be\n+used to initialize `struct`s with fields which are inaccessible due to privacy.\n+*Functional record updates (FRU)* can reduce noise when a `struct` derives\n+`Default`, but are also invalid when the `struct` has inaccessible fields.\n+\n+To work around these shortcomings, you can create constructor functions:\n+\n+```rust\n+struct Foo {\n+    alpha: &'static str,\n+    beta: bool,\n+    gamma: i32,\n+}\n+\n+impl Foo {\n+    /// Constructs a `Foo`.\n+    fn new(alpha: &'static str, gamma: i32) -> Self {\n+        Self {\n+            alpha,\n+            beta: true,\n+            gamma\n+        }\n+    }\n+}\n+\n+let foo = Foo::new(\"Hello\", 42);\n+```\n+\n+[`process::Command`]: https://doc.rust-lang.org/stable/std/process/struct.Command.html\n+\n+The problem with a constructor is that you need one for each combination\n+of fields a caller can supply. To work around this, you can use builders,\n+such as [`process::Command`] in the standard library.\n+Builders enable more advanced initialization, but require additional boilerplate.\n+\n+As a part of this RFC, a solution is proposed for improving `struct` literal\n+ergonomics such that they can be used for `struct`s with private fields,\n+and to reduce boilerplate for simple scenarios (as seen in the [summary]).\n+This is achieved by letting callers omit fields from initialization when\n+a default is specified for that field.\n+\n+Field defaults allow a caller to initialise a `struct` with default values\n+without needing builders or a constructor function:\n+\n+```rust\n+struct Foo {\n+    alpha: &'static str = \"Hello\",\n+    beta: bool = true,\n+    gamma: i32 = 42,\n+}\n+\n+// Overriding a single field default:\n+let foo = Foo {\n+    beta: false,\n+    ..\n+};\n+\n+// Override multiple field defaults:\n+let foo = Foo {\n+    alpha: \"Overriden\",\n+    gamma: 1,\n+    ..\n+};\n+\n+// Override no field defaults:\n+let foo = Foo { .. };\n+```\n+\n+### `PhantomData` ergonomics\n+\n+[nomicon]: https://doc.rust-lang.org/nightly/nomicon/phantom-data.html\n+\n+Say that you want to define our own `Vec<T>` type. As the [nomicon] says,\n+you need to use [PhantomData] to make sure that drop-checking is sound like so:\n+\n+```rust\n+use std::marker::PhantomData;\n+\n+struct Vec<T> {\n+    data: *const T, // *const for variance!\n+    len: usize,\n+    cap: usize,\n+    _marker: PhantomData<T>,\n+}\n+```\n+\n+You then go on to define some operations for `Vec<T>`:\n+\n+```rust\n+impl<T> Vec<T> {\n+    pub fn new() -> Self {\n+        Self {\n+            // other fields...\n+            _marker: PhantomData,\n+        }\n+    }\n+\n+    pub fn with_capacity(capacity: usize) -> Self {\n+        Self {\n+            // other fields...\n+            _marker: PhantomData,\n+        }\n+    }\n+}\n+```\n+\n+Here, `_marker: PhantomData` is just provided to satisfy the compiler.\n+`PhantomData` carries no useful information since it is a ZST.\n+Therefore, the result of having to add a field of type `PhantomData`\n+is a regression to ergonomics throughout. With default values you can\n+improve the situation slightly and provide the value in a single place:\n+\n+```rust\n+use std::marker::PhantomData;\n+\n+struct Vec<T> {\n+    data: *const T, // *const for variance!\n+    len: usize,\n+    cap: usize,\n+    _marker: PhantomData<T> = PhantomData,\n+}\n+```\n+\n+You then go on to define some operations for `Vec<T>`:\n+\n+```rust\n+impl<T> Vec<T> {\n+    pub fn new() -> Self {\n+        Self {\n+            // other fields...\n+            ..\n+        }\n+    }\n+\n+    pub fn with_capacity(capacity: usize) -> Self {\n+        Self {\n+            // other fields...\n+            ..\n+        }\n+    }\n+}\n+```\n+\n+### Defaults for `enum`s\n+\n+So far, you've have seen how ergonomics were improved for `struct`s.\n+For `enum`s, FRU cannot be used as for structs and neither can\n+`#[derive(Default)]` be used for each variant or the entire enum.\n+Instead, at best, a constructor function can be offered for each variant.\n+For a large enum which for example encodes an expression language such\n+this could become quite a lot of variants.\n+\n+By allowing each individual variant of an `enum` to have default values,\n+a more profound can achieve a more profound improvement to ergonomics\n+than for `struct`s. For example, you may write:\n+\n+```rust\n+enum Foo<'a> {\n+    Bar {\n+        alpha: u8 = 42,\n+        beta: &'a str = \"beta's default value\",\n+    },\n+    Baz {\n+        gamma: Vec<u8> = Vec::new(),\n+        delta: f32\n+    }\n+}\n+```\n+\n+and then these defaults may be used like so:\n+\n+```rust\n+let a = Foo::Bar { .. };\n+let b = Foo::Bar { alpha: 1, .. };\n+let c = Foo::Bar { beta: \"another beta\", .. };\n+\n+let d = Foo::Baz { delta: 1.0, .. };\n+```\n+\n+## `#[derive(Default)]` in more cases\n+\n+The `#[derive(..)]` (\"custom derive\") mechanism works by defining procedural\n+*macros*. Because they are macros, these operate on abstract *syntax* and\n+don't have more information available. Therefore, when you `#[derive(Default)]`\n+on a data type definition as with:\n+\n+```rust\n+#[derive(Default)]\n+struct Foo {\n+    bar: u8,\n+    baz: String,\n+}\n+```\n+\n+it only has the immediate \"textual\" definition available to it.\n+\n+Because Rust currently does not have an in-language way to define default values,\n+you cannot `#[derive(Default)]` in the cases where you are not happy with the\n+natural default values that each field's type provides. By extending the syntax\n+of Rust such that default values can be provided, `#[derive(Default)]` can be\n+used in many more circumstances and thus boilerplate is further reduced.\n+\n+Currently, `#[derive(Default)]` is not usable for `enum`s. To rectify this\n+situation and to allow enum variants to take advantage of their newfound\n+ability to have default field values, a `#[default]` attribute is introduce\n+that can be attached to variants. This allows you to use `#[derive(Default)]`\n+on enums wherefore you can now write:\n+\n+```rust\n+// From rocket:\n+\n+#[derive(Default)]\n+enum Referrer {\n+    #[default]\n+    NoReferrer,\n+    NoReferrerWhenDowngrade,\n+    ...\n+}\n+\n+#[derive(Default)]\n+enum ExpectCt {\n+    #[default]\n+    Enforce {\n+        duration: Duration = Duration::days(30)\n+    },\n+    ...\n+}\n+\n+// From git2:\n+\n+#[derive(Default)]\n+enum FileFavor {\n+    #[default]\n+    Normal,\n+    Ours,\n+    Theirs,\n+    Union,\n+}\n+```\n+\n+## Clearer documentation and more local reasoning\n+\n+Providing good defaults when such exist is part of any good design that makes\n+a physical tool, UI design, or even data-type more ergonomic and easily usable.\n+However, that does not mean that the defaults provided can just be ignored\n+and that they need not be understood. This is especially the case when you\n+are moving away from said defaults and need to understand what they were.\n+Furthermore, it is not too uncommon to see authors writing in the documentation\n+of a data-type that a certain value is the default.\n+\n+All in all, the defaults of a data-type are therefore important properties.\n+By encoding the defaults right where the data-type is defined gains can be made\n+in terms of readability particularly wrt. the *skimmability* of code.\n+In particular, it is easier to see what the defaults are if you can directly\n+look at the `rustdoc` page and read:\n+\n+```rust\n+#[derive(Default)]\n+enum Foo {\n+    #[default]\n+    Bar {\n+        alpha: u8 = 42,\n+    },\n+    Baz {\n+        beta: u16 = 24,\n+        gamma: bool,\n+    }\n+}\n+```\n+\n+This way, you do not need to open up the code of the `Default` implementation\n+to see what the values encoded are.\n+\n+## Usage by other `#[derive(..)]` macros\n+\n+[`serde`]: https://serde.rs/attributes.html\n+\n+Custom derive macros exist that have a notion of or use default values.\n+\n+### `serde`\n+\n+For example, the [`serde`] crate provides a `#[serde(default)]` attribute that\n+can be used on `struct`s, and fields. This will use the field's or type's\n+`Default` implementations. This works well with field defaults; `serde` can\n+either continue to rely on `Default` implementations in which case this RFC\n+facilitates specification of field defaults; or it can directly use the default\n+values provided in the type definition.\n+\n+### `structopt`\n+\n+Another example is the `structopt` crate with which you can write:\n+\n+```rust\n+#[derive(Debug, StructOpt)]\n+#[structopt(name = \"example\", about = \"An example of StructOpt usage.\")]\n+struct Opt {\n+    /// Set speed\n+    #[structopt(short = \"s\", long = \"speed\", default_value = \"42\")]\n+    speed: f64,\n+    ...\n+}\n+```\n+\n+By having default field values in the language, `structopt` could let you write:\n+\n+```rust\n+#[derive(Debug, StructOpt)]\n+#[structopt(name = \"example\", about = \"An example of StructOpt usage.\")]\n+struct Opt {\n+    /// Set speed\n+    #[structopt(short = \"s\", long = \"speed\")]\n+    speed: f64 = 42,\n+    ...\n+}\n+```\n+\n+### `derive_builder`\n+\n+[`derive_builder`]: https://docs.rs/derive_builder/0.7.0/derive_builder/#default-values\n+\n+A third example comes from the crate [`derive_builder`]. As the name implies,\n+you can use it to `#[derive(Builder)]`s for your types. An example is:\n+\n+```rust\n+#[derive(Builder, Debug, PartialEq)]\n+struct Lorem {\n+    #[builder(default = \"42\")]\n+    pub ipsum: u32,\n+}\n+```\n+\n+### `proptest_derive`\n+\n+The yet to be released `#[derive(Arbitrary)]` custom derive macro also has a\n+notion of defaults; for example, you may write:\n+\n+```rust\n+#[derive(Debug, Arbitrary)]\n+struct Foo {\n+    bar: usize,\n+    #[proptest(value = \"42\")]\n+    baz: usize,\n+}\n+```\n+\n+This will generate random `usize`s for `bar` and fix the value of `baz` to `42`.\n+One could instead imagine writing:\n+\n+```rust\n+#[derive(Debug, Arbitrary)]\n+struct Foo {\n+    bar: usize,\n+    #[proptest(default)]\n+    baz: usize = 42,\n+}\n+```\n+\n+This would then fix the value of `baz` to `42`.\n+\n+### Conclusion\n+\n+As seen in the previous sections, rather than make deriving `Default`\n+more magical, by allowing default field values in the language,\n+user-space custom derive macros can make use of them.\n+\n+# Guide-level explanation\n+[guide-level-explanation]: #guide-level-explanation\n+\n+## Providing field defaults\n+\n+Consider a data-type such as (1):\n+\n+```rust\n+pub struct Probability {\n+    value: f32,\n+}\n+```\n+\n+You'd like encode the default probability value to be `0.5`;\n+With this RFC now you can provide such a default directly where `Probability`\n+is defined like so (2):\n+\n+```rust\n+pub struct Probability {\n+    value: f32 = 0.5,\n+}\n+```\n+\n+Having done this, you can now construct a `Probability` with a struct\n+initializer and leave `value` out to use the default (3):\n+\n+```rust\n+let prob = Probability { .. };\n+```\n+\n+## Deriving `Default`\n+\n+Previously, you might have instead implemented the `Default` trait like so (4):\n+\n+```rust\n+impl Default for Probability {\n+    fn default() -> Self {\n+        Self { value: 0.5 }\n+    }\n+}\n+```\n+\n+You can now shorten this to (5):\n+\n+```rust\n+impl Default for Probability {\n+    fn default() -> Self {\n+        Self { .. }\n+    }\n+}\n+```\n+\n+However, since you had specified `value: f32 = 0.5` in the definition of\n+`Probability`, you can take advantage of that to write the more simpler\n+and more idiomatic (6):\n+\n+```rust\n+#[derive(Default)]\n+pub struct Probability {\n+    value: f32 = 0.5,\n+}\n+```\n+\n+Having done this, a `Default` implementation equivalent to the one in (5)\n+will be generated for you.\n+\n+## More fields\n+\n+As you saw in the [summary], you are not limited to a single field and all\n+fields must not have any defaults associated with them. Instead, you can\n+freely mix and match (7):\n+\n+```rust\n+#[derive(Default)]\n+struct ExprType {\n+    expr: Box<Expr>,\n+    ty: Box<Ty>\n+    attrs: Vec<Attribute> = Vec::new(),\n+}\n+```\n+\n+Given this definition, you can omit `attrs` and `color_token` (8):\n+\n+```rust\n+let ascribe = ExprType { expr: make_expr(), ty: make_type(), .. };\n+```\n+\n+You can also elect to override the provided default (9):\n+\n+```rust\n+let ascribe = ExprType {\n+    attr: vec![\n+        parse_quote!(#[allow(unused_parens)]),\n+        parse_quote!(#[deny(other_lint)]),\n+    ],\n+    expr: parse_quote!((1 + 2)),\n+    ty: parse_quote!(u8),\n+}\n+```\n+\n+## Default fields values are [`const` context]s\n+\n+[`const` context]: https://github.com/rust-lang-nursery/reference/blob/66ef5396eccca909536b91cad853f727789c8ebe/src/const_eval.md#const-context\n+\n+As you saw in (7), `Vec::new()`, a function call, was used.\n+However, this assumes that `Vec::new` is a *`const fn`*. That is, when you\n+provide a default value `field: Type = value`, the given `value` must be a\n+*constant expression* such that it is valid in a [`const` context].\n+Therefore, you cannot write something like (10):\n+\n+```rust\n+fn launch_missilies() -> Result<(), LaunchFailure> {\n+    authenticate()?;\n+    begin_launch_sequence()?;\n+    ignite()?;\n+    Ok(())\n+}\n+\n+struct BadFoo {\n+    bad_field: u8 = {\n+        launch_missilies().unwrap();\n+        42\n+    },\n+}\n+```\n+\n+Since launching missiles interacts with the real world and has *side-effects*\n+in it, it is not possible to do that in a `const` context since it may violate\n+deterministic compilation.\n+\n+## Privacy interactions\n+\n+In examples thus far, initialization literal expressions `Foo { bar, .. }` have\n+been used in the same module as where the type constructed was defined in.\n+\n+Let's now consider a scenario where this is not the case (11):\n+\n+```rust\n+pub mod foo {\n+    pub struct Alpha {\n+        beta: u8 = 42,\n+        gamma: bool = true,\n+    }\n+}\n+\n+mod bar {\n+    fn baz() {\n+        let x = Alpha { .. };\n+    }\n+}\n+```\n+\n+Despite `foo::bar` being in a different module than `foo::Alpha` and despite\n+`beta` and `gamma` being private to `foo::bar`, a Rust compiler will accept\n+the above snippet. It is legal because when `Alpha { .. }` expands to\n+`Alpha { beta: 42, gamma: true }`, the fields `beta` and `gamma` are considered\n+in the context of `foo::Alpha`'s *definition site* rather than `bar::baz`'s\n+definition site.\n+\n+## `#[non_exhaustive]` interactions\n+\n+[RFC 2008]: https://github.com/rust-lang/rfcs/blob/master/text/2008-non-exhaustive.md#structs-1\n+\n+[RFC 2008] introduced the attribute `#[non_exhaustive]` that can be placed\n+on `struct`, `enum`, and `enum` variants. The RFC notes that upon defining\n+a `struct` in *crate A* such as (12):\n+\n+```rust\n+#[non_exhaustive]\n+pub struct Config {\n+    pub width: u16,\n+    pub height: u16,\n+}\n+```\n+\n+it is **_not_** possible to initialize a `Config` in a different *crate B* (13):\n+\n+```rust\n+let config = Config { width: 640, height: 480 };\n+```\n+\n+This is forbidden when `#[non_exhaustive]` is attached because the purpose of\n+the attribute is to permit adding fields to `Config` without causing a\n+breaking change. However, the RFC goes on to note that you can pattern match\n+if you allow for the possibility of having fields be ignored with `..` (14):\n+\n+```rust\n+let Config { width, height, .. } = config;\n+```\n+\n+Because this RFC gives a way to have default field values, you can now simply\n+invert the pattern expression and initialize a `Config` like so (15):\n+\n+```rust\n+let config = Config { width, height, .. };\n+```\n+\n+## Defaults for `enum`s\n+\n+The ability to give fields default values is not limited to `struct`s.\n+Fields of `enum` variants can also be given defaults (16):\n+\n+```rust\n+enum Ingredient {\n+    Tomato {\n+        color: Color = Color::Red,\n+        taste: TasteQuality,\n+    },\n+    Onion {\n+        color: Color = Color::Yellow,\n+    }\n+}\n+```\n+\n+Given these defaults, you can then proceed to initialize `Ingredient`s\n+as you did with `struct`s (17):\n+\n+```rust\n+let sallad_parts = vec![\n+    Ingredient::Tomato { taste: Yummy, .. },\n+    Ingredient::Tomato { taste: Delicious, color: Color::Green, },\n+    Ingredient::Onion { .. },\n+];\n+```\n+\n+Note that `enum` variants have public fields and in today's Rust,\n+this cannot be controlled with visibility modifiers on variants.\n+\n+Furthermore, when `#[non_exhaustive]` is specified directly on an `enum`,\n+it has no interaction with the defaults values and the ability to construct\n+variants of said enum. However, as specified by [RFC 2008], `#[non_exhaustive]`\n+is permitted on variants. When that occurs, the behaviour is the same as if\n+it had been attached to a `struct` with the same fields.\n+\n+### Specifying the `#[default]` variant\n+\n+The ability to add default values to fields of `enum` variants does not mean\n+that you can suddenly `#[derive(Default)]` on the enum. A Rust compiler will\n+still have no idea which variant you intended as the default.\n+This RFC adds the ability to mark one variant with `#[default]` (18):\n+\n+```rust\n+#[derive(Default)]\n+enum Ingredient {\n+    Tomato {\n+        color: Color = Color::Red,\n+        taste: TasteQuality,\n+    },\n+    Onion {\n+        color: Color = Color::Yellow,\n+    },\n+    #[default]\n+    Lettuce,\n+}\n+```\n+\n+Now the compiler does know that `Ingredient::Lettuce` should be considered\n+the default and will accordingly generate an appropriate implementation of\n+`Default for Ingredient` (19):\n+\n+```rust\n+impl Default for Ingredient {\n+    fn default() -> Self {\n+        Ingredient::Lettuce\n+    }\n+}\n+```\n+\n+Note that after any `#[cfg_attr(..)]`-stripping has occurred, it is an error\n+to have `#[default]` specified on more than one variant.\n+\n+# Reference-level explanation\n+[reference-level-explanation]: #reference-level-explanation\n+\n+## Field default values\n+\n+### Grammar\n+\n+Let the grammar of record fields in `struct`s and `enum` variants be defined\n+like so (in the `.lyg` notation):\n+\n+```rust\n+RecordField = attrs:OuterAttr* vis:Vis? name:IDENT \":\" ty:Type;\n+```\n+\n+Then, `RecordField` is changed into:\n+\n+```rust\n+RecordField = attrs:OuterAttr* vis:Vis? name:IDENT \":\" ty:Type { \"=\" def:Expr }?;\n+```\n+\n+Further, given the following partial definition for the expression grammar:\n+\n+```rust\n+Expr = attrs:OuterAttr* kind:ExprKind;\n+ExprKind =\n+  | ...\n+  | Struct:{ path:Path \"{\" attrs:InnerAttr* fields:StructExprFieldsAndBase \"}\" }\n+  ;\n+\n+StructExprFieldsAndBase =\n+  | Fields:{ fields:StructExprField* % \",\" \",\"? }\n+  | Base:{ \"..\" base:Expr }\n+  | FieldsAndBase:{ fields:StructExprField+ % \",\" \",\" \"..\" base:Expr }\n+  ;\n+StructExprField = attrs:OuterAttr* kind:StructExprFieldKind;\n+StructExprFieldKind =\n+  | Shorthand:IDENT\n+  | Explicit:{ field:FieldName \":\" expr:Expr }\n+  ;\n+```\n+\n+the rule `StructExprFieldsAndBase` is extended with:\n+\n+```rust\n+StructExprFieldsAndBase =| FieldsAndDefault:{ fields:StructExprField+ % \",\" \",\" \"..\" };\n+```\n+\n+### Static semantics\n+\n+#### Defining defaults\n+\n+Given a `RecordField` where the default is specified, i.e.:\n+\n+```rust\n+RecordField = attrs:OuterAttr* vis:Vis? name:IDENT \":\" ty:Type \"=\" def:Expr;\n+```\n+\n+all the following rules apply when type-checking:\n+\n+1. The expression `def` must be a constant expression.\n+\n+2. The expression `def` must unify with the type `ty`.\n+\n+When lints check attributes such as `#[allow(lint_name)]` are placed on a\n+`RecordField`, it also applies to `def` if it exists.\n+\n+#### Initialization expressions\n+\n+Given an expression `τ` of form (e.g. `Foo { x: 1, .. }`):\n+\n+```rust\n+path:Path \"{\" attrs:InnerAttr* fields:StructExprField+ % \",\" \",\" \"..\" \"}\"\n+```\n+\n+all the following rules apply when type-checking:\n+\n+1. All `fields` in `τ` mentioned must exist in the `struct` or `enum` variant\n+   referenced by `path`. No field in `fields` may be mentioned twice.\n+\n+2. For each `field: expr` pair in `fields` of `τ`,\n+   `expr` must unify with the type of `field` in the `struct`\n+   or `enum` variant referenced by `path`.\n+\n+3. For each `field: expression` pair in `fields` of `τ`,\n+   `field` must be visible in the context which `τ` occurs in.\n+\n+4. For each field `f` in `τ` *not* mentioned in `fields`, a default value must\n+   exist for `f` in the `struct` or `enum` variant referenced by `path`.\n+\n+---------------------\n+\n+**Lemma 1:** If `τ` is of a type `σ` where `σ: Sync`, and if all `field: expr`\n+has an `expr` component which is a valid constant expression, then `τ` is\n+also a valid constant expression.\n+\n+**Proof:** It trivially holds that if all `expr`s in `τ` are\n+constant expressions and all default values for fields omitted\n+are also constant expressions, then `τ` is a constant expression.\n+\n+**Lemma 2:** If an expression `x` of form `Path { .. }` is of a type `σ` where\n+`σ: Sync`, then `x` is a constant expression.\n+\n+**Proof:** `x` is a special case of `τ` with all fields according to the default\n+values. Since there are no explicitly provided fields, by Lemma 1 it holds.\n+\n+### Dynamic semantics\n+\n+Given a well-formed expression `τ` according to the form aforementioned,\n+the operational semantics is the same as the semantics of an expression\n+`path { new_fields }` with `new_fields = fields ∪ default_fields` where:\n+\n++ `∪` computes the left-biased union where equal elements are determined\n+  solely on equality of field names.\n+\n++ `fields` are the set of explicitly given `field: expr` pairs.\n+\n++ `default_fields` are the fields in `τ`'s data-type or variant which\n+  have provided default values.\n+\n+## `#[default]` on `enum`s\n+\n+A built-in attribute `#[default]` is provided the compiler and may be legally\n+placed solely on `enum` variants. The attribute has no semantics on its own.\n+Placing the attribute on anything else will result in a compilation error.\n+Furthermore, if after `cfg`-stripping and macro expansion is done,\n+the attribute occurs on more than one variant of the same `enum` data-type,\n+this will also result in a compilation error.\n+\n+## `#[derive(Default)]`\n+\n+When generating an implementation of `Default` for a `struct` named `$s` on\n+which `#[derive(Default)]` has been attached, the compiler will omit all fields\n+which have default values provided in the `struct`. The the associated function\n+`default` shall then be defined as (where `$f_i` denotes a vector of the fields\n+of `$s`):\n+\n+```rust\n+fn default() -> Self {\n+    $s { $f_i: Default::default(), .. }\n+}\n+```\n+\n+Placing `#[derive(Default)]` on an `enum` named `$e` is permissible iff that\n+enum has some variant `$v` with `#[default]` on it. In that event, the compiler\n+shall generate an implementation of `Default` where the function `default`\n+is defined as (where `$f_i` denotes a vector of the fields of `$e::$v`):\n+\n+```rust\n+fn default() -> Self {\n+    $e::$v { $f_i: Default::default(), .. }\n+}\n+```\n+\n+# Drawbacks\n+[drawbacks]: #drawbacks\n+\n+The usual drawback of increasing the complexity of the language applies.\n+However, the degree to which complexity is increased is not substantial.\n+\n+In particular, the syntax `Foo { .. }` mirrors the identical and already\n+existing pattern syntax. This makes the addition of `Foo { .. }` at worst\n+low-cost and potentially cost-free.\n+\n+The main complexity comes instead from introducing `field: Type = expr`.\n+However, as seen in the [prior-art], there are several widely used languages\n+that have a notion of field / property / instance-variable defaults.\n+Therefore, the addition is intuitive and thus the cost is seen as limited.\n+\n+# Rationale and alternatives\n+[rationale-and-alternatives]: #rationale-and-alternatives\n+\n+Besides the given [motivation], there are some specific design choices\n+worthy of more in-depth discussion, which is the aim of this section.\n+\n+## Provided associated items as precedent\n+\n+While Rust does not have any support for default values for fields or for\n+formal parameters of functions, the notion of defaults are not foreign to Rust.\n+\n+Indeed, it is possible to provide default function bodies for `fn` items in\n+`trait` definitions. For example:\n+\n+```rust\n+pub trait PartialEq<Rhs: ?Sized = Self> {\n+    fn eq(&self, other: &Rhs) -> bool;\n+\n+    fn ne(&self, other: &Rhs) -> bool { // A default body.\n+        !self.eq(other)\n+    }\n+}\n+```\n+\n+In traits, `const` items can also be assigned a default value. For example:\n+\n+```rust\n+trait Foo {\n+    const BAR: usize = 42; // A default value.\n+}\n+```\n+\n+Thus, to extend Rust with a notion of field defaults is not an entirely alien\n+concept.\n+\n+## Pattern matching follows construction\n+\n+[dual]: https://en.wikipedia.org/wiki/Duality_(mathematics)\n+\n+In mathematics there is a notion of one thing being the *[dual]* of another.\n+Loosely speaking, duals are often about inverting something.\n+In Rust, one example of such an inversion is expressions and patterns.\n+\n+Expressions are used to *build up* and patterns *break apart*;\n+While it doesn't hold generally, a principle of language design both in Rust\n+and other languages with with pattern matching has been that the syntax for\n+patterns should, to the extent possible, follow that of expressions.\n+\n+For example:\n+\n++ You can match on or build up a struct with `Foo { field }`.\n+  For patterns this will make `field` available as a binding\n+  while for expressions the binding `field` will be used to build a `Foo`.\n+\n+  For a tuple struct, `Foo(x)` will work both for construction and matching.\n+\n++ If you want to be more flexible, both patterns and expressions permit\n+  `Foo { field: bar }`.\n+\n++ You can use both `&x` to dereference and bind to `x` or\n+  construct a reference to `x`.\n+\n++ An array can be constructed with `[a, b, c, d]` and the same is a valid\n+  pattern for destructuring an array.\n+\n+The reason why matching should follow construction is that it makes languages\n+easier to understand; you simply learn the expression syntax and then reuse\n+it to run the process in reverse.\n+\n+In some places, Rust could do a better job than it currently does of adhering to\n+this principle. In this particular case, the pattern syntax `Foo { a, b: c, .. }`\n+has no counterpart in the expression syntax. This RFC rectifies this by\n+permitting `Foo { a, b: c, .. }` as an expression syntax; this is identical\n+to the expression syntax and thus consistency has been gained.\n+\n+However, it is not merely sufficient to use the same syntax for expressions;\n+the semantics also have to be similar in kind for things to work out well.\n+This RFC argues that this is the case because in both contexts, `..` indicates\n+something partially ignorable is going on: \"I am *destructuring*/*constructing*\n+this struct, and by the way there are some more fields I don't care about\n+*and let's* drop those* / *and let's fill in with default values*\".\n+In a way, the use of `_` to mean both a catch-all pattern and type / value\n+placeholder is similar to `..`; in the case of `_` both cases indicate something\n+unimportant going on. For patterns, `_` matches everything and doesn't give\n+access to the value; for types, the placeholder is just an unbounded inference\n+variable.\n+\n+## On privacy\n+\n+This RFC specifies that when field defaults are specified, the desugaring\n+semantics of `Foo { .. }` spans `field: default_value` with the context in\n+which the type is defined as opposed to where `Foo { .. }` occurs.\n+In other words, the following is valid:\n+\n+```rust\n+pub mod alpha {\n+    pub struct Foo {\n+        field: u8 = 42,\n+    }\n+}\n+\n+use alpha::Foo;\n+\n+mod beta {\n+    // `field` isn't visible here.\n+    fn bar() -> Foo {\n+        Foo { .. } // OK!\n+    }\n+}\n+```\n+\n+By permitting the above snippet, you are able to construct a default value\n+for a type more ergonomically with `Foo { .. }`. Since it isn't possible for\n+functions in `beta` to access `field`'s value, the value `42` or any other\n+remains at all times private to `alpha`. Therefore, privacy, and by extension\n+soundness, is preserved.\n+\n+If a user wishes to keep other modules from constructing a `Foo` with\n+`Foo { .. }` they can simply add, or keep, one private field without a default.\n+Situations where this can be important include those where `Foo` is some token\n+for some resource and where fabricating a `Foo` may prove dangerous or worse\n+unsound. This is however no different than carelessly adding `#[derive(Default)]`.\n+\n+## On `const` contexts\n+\n+To recap, the expression a default value is computed with must be constant one.\n+There are many reasons for this restriction:\n+\n++ If *determinism* is not enforced, then just by writing the following snippet,\n+  the condition `x == y` may fail:\n+\n+  ```rust\n+  let x = Foo { .. };\n+  let y = Foo { .. };\n+  ```\n+\n+  This contributes to surprising behaviour overall.\n+\n+  Now you may object with an observation that if you replace `Foo { .. }` with\n+  `make_foo()` then a reader no longer know just from the syntactic form whether\n+  `x == y` is still upheld. This is indeed true. However, there is a general\n+  expectation in Rust that a function call may not behave deterministically.\n+  Meanwhile, for the syntactic form `Foo { .. }` and with default values,\n+  the whole idea is that they are something that doesn't require close attention.\n+\n++ The broader class of problem that non-determinism highlights is that of\n+  *side*-effects. These effects wrt. program behaviour are prefixed with\n+  *\"side\"* because they happen without being communicated in the type system\n+  or more specifically in the inputs and outputs of a function.\n+\n+  In general, it is easier to do formal verification of programs that lack\n+  side-effects. While programming with Rust, requirements are usually not\n+  that demanding and robust. However, the same properties that make pure\n+  logic easier to formally verify also make for more *local reasoning*.\n+\n+  [reasoning footprint]: https://blog.rust-lang.org/2017/03/02/lang-ergonomics.html#implicit-vs-explicit\n+\n+  _By requring default field values to be `const` contexts, global reasoning\n+  can be avoided. Thus, the [reasoning footprint] for `Foo { .. }` is reduced._\n+\n++ By restricting ourselves to `const` contexts, you can be sure that default\n+  literals have a degree of *cheapness*.\n+\n+  While `const` expressions form a turing complete language and therefore\n+  have no limits to their complexity other than being computable,\n+  these expressions are evaluated at *compile time*.\n+  Thus, *`const` expressions cannot have unbounded complexity at run-time*.\n+  At most, `const` expressions can create huge arrays and similar cases;\n+\n+  Ensuring that `Foo { .. }` remains relatively cheap is therefore important\n+  because there is a general expectation that literal expressions have a small\n+  and predictable run-time cost and are trivially predictable.\n+  This is particularly important for Rust since this is a language that aims\n+  to give a high degree of control over space and time as well as predictable\n+  performance characteristics.\n+\n++ Keeping default values limited to `const` expressions ensures that if\n+  the following situation develops:\n+\n+  ```rust\n+  // Crate A:\n+  pub struct Foo {\n+      bar: u8 = const_expr,\n+  }\n+\n+  // Crate B:\n+  const fn baz() -> Foo {\n+      Foo { .. }\n+  }\n+  ```\n+\n+  then crate A cannot suddenly, and unawares, cause a semver breakage\n+  for crate B by replacing `const_expr` with `non_const_expr` since\n+  the compiler would reject such a change (see lemmas 1-2).\n+  Thus, enforcing constness gives a helping hand in respecting semantic version.\n+\n+  Note that if Rust would ever gain a mechanism to state that a\n+  function will not diverge, e.g.:\n+\n+  ```rust\n+  nopanic fn foo() -> u8 { 42 } // The weaker variant; more easily attainable.\n+  total fn bar() -> u8 { 24 } // No divergence, period.\n+  ```\n+\n+  then the same semver problem would manifest itself for those types of\n+  functions. However, Rust does not have any such enforcement mechanism\n+  right now and if it did, it is generally harder to ensure that a function\n+  is total than it is to ensure that it is deterministic; thus, while\n+  it is regrettable, this is an acceptable trade-off.\n+\n++ Finally, note that `const fn`s, when coupled with planned future extensions,\n+  can become quite expressive. For example, it is already planned that `loop`s,\n+  `match`es, `let` statements, and `panic!(..)`s will be allowed.\n+  Another feasible extension in the future is allocation.\n+\n+  Therefore, constant expressions should be enough to satisfy most expressive\n+  needs.\n+\n+## Instead of `Foo { ..Default::default() }`\n+\n+As an alternative to the proposed design is either explicitly writing out\n+`..Default::default()` or extending the language such that `Foo { .. }` becomes\n+sugar for `Foo { ..Default::default() }`. While the latter idea does not satisfy\n+any of the [motivation] set out, the former does to a small extent.\n+\n+In particular, `Foo { .. }` as sugar slightly improves ergonomics.\n+However, it has some notable problems:\n+\n++ Because it desugars to `Foo { ..Default::default() }` it cannot be required\n+  that the expression is a constant one; This carries all the problems noted in\n+  the previous section on why default field values should be a `const` context.\n+\n++ It provides zero improvements to the ergonomics of *specifying* defaults,\n+  only for using them. Arguably, the most important aspect of this RFC is\n+  not the syntax `Foo { .. }` but rather the ability to provide default values\n+  for field.\n+\n++ By extension, the improvement to documentation clarity is lost.\n+\n++ No improvement is provided for `enum`s at all; in particular, you cannot\n+  `impl Default for Enum::Variant { .. }` while this RFC enables that.\n+\n++ The trait `Default` must now become a `#[lang_item]`. This is a sign of\n+  increasing the overall magic in the system; meanwhile, this proposal makes\n+  the default values provided usable by other custom derive macros.\n+\n+Thus in conclusion, while desugaring `..` to `Default::default()` has lower cost,\n+it also provides significantly less value to the point of not being worth it.\n+\n+## `..` is useful as a marker\n+\n+One possible change to the current design is to permit filling in defaults\n+by simply writing `Foo {}`; in other words, `..` is simply dropped from the\n+expression.\n+\n+Among the benefits are:\n+\n++ To enhance ergonomics of initialization further.\n+\n++ To introduce less syntax.\n+\n++ To be more in line with how other languages treat default values.\n+\n+Among the drawbacks are:\n+\n++ The syntax `Foo { .. }` is no longer introduced to complement the identical\n+  pattern syntax. As aforementioned, destruction (and pattern matching)\n+  generally attempts to follow construction in Rust. Because of that,\n+  introducing `Foo { .. }` is essentially cost-free in terms of the complexity\n+  budget. It is arguably even cost-negative.\n+\n++ By writing `Foo { .. }`, you have there is explicit indication that default\n+  values are being used; this enhances local reasoning further.\n+\n+# Prior art\n+[prior-art]: #prior-art\n+\n+## Other languages\n+\n+This selection of languages are not exhaustive; rather, a few notable or\n+canonical examples are used instead.\n+\n+### Java\n+\n+In Java it is possible to assign default values, computed by any expression,\n+to an instance variable; for example, you may write:\n+\n+```java\n+class Main {\n+    public static void main(String[] args) {\n+        new Foo();\n+    }\n+\n+    public static int make_int() {\n+        System.out.println(\"I am making an int!\");\n+        return 42;\n+    }\n+\n+    static class Foo {\n+        private int bar = Main.make_int();\n+    }\n+}\n+```\n+\n+When executing this program, the JVM will print the following to `stdout`:\n+\n+```\n+I am making an int!\n+```\n+\n+Two things are worth noting here:\n+\n+1. It is possible to cause arbitrary side effects in the expression that\n+   computes the default value of `bar`. This behaviour is unlike that which\n+   this RFC proposes.\n+\n+2. It is possible to construct a `Foo` which uses the default value of `bar`\n+   even though `bar` has `private` visibility. This is because default values\n+   act as syntactic sugar for how the default constructor `Foo()` should act.\n+   There is no such thing as constructors in Rust. However, the behaviour\n+   that Java has is morally equivalent to this RFC since literals are\n+   constructor-like and because this RFC also permits the usage of defaults\n+   for private fields where the fields are not visible.\n+\n+### Scala\n+\n+Being a JVM language, Scala builds upon Java and retains the notion of default\n+field values. For example, you may write:\n+\n+```scala\n+case class Person(name: String = make_string(), age: Int = 42)\n+\n+def make_string(): String = {\n+    System.out.println(\"foo\");\n+    \"bar\"\n+}\n+\n+var p = new Person(age = 24);\n+System.out.println(p.name);\n+```\n+\n+As expected, this prints `foo` and then `bar` to the terminal.\n+\n+### Kotlin\n+\n+Kotlin is similar to both Java and Scala; here too can you use defaults:\n+\n+```kotlin\n+fun make_int(): Int {\n+    println(\"foo\");\n+    return 42;\n+}\n+\n+class Person(val age: Int = make_int());\n+\n+fun main() {\n+    Person();\n+}\n+```\n+\n+Similar to Java and Scala, Kotlin does also permit side-effects in the default\n+values because both languages have no means of preventing the effects.\n+\n+### C#\n+\n+Another language with defaults in the OO list is C#.\n+The behaviour similar to Java:\n+\n+```csharp\n+class Foo {\n+    int bar = 42;\n+}\n+```\n+\n+### C++\n+\n+Another language in the object oriented family is C++. It also affords default\n+values like so:\n+\n+```cpp\n+#include <iostream>\n+\n+int make_int() {\n+    std::cout << \"hello\" << std::endl; // As in Java.\n+    return 42;\n+}\n+\n+class Foo {\n+    private:\n+        int bar = make_int();\n+    public:\n+        int get_bar() {\n+          return this->bar;\n+        }\n+};\n+\n+int main() {\n+    Foo x;\n+    std::cout << x.get_bar() << std::endl;\n+}\n+```\n+\n+In C++ it is still the case that the defaults are usable due to constructors.\n+And while the language has `constexpr` to enforce the ability to evaluate\n+something at compile time, as can be seen in the snippet above, no such\n+requirement is placed on default field values.\n+\n+### Swift\n+\n+[Swift]: https://docs.swift.org/swift-book/LanguageGuide/Initialization.html\n+\n+A language which is closer to Rust is [Swift] and it allows for default values:","path":"text/0000-default-field-values.md","position":1266,"original_position":1266,"commit_id":"ff081b8b792bb54098c76a612c83fc9a20c2330e","original_commit_id":"ff081b8b792bb54098c76a612c83fc9a20c2330e","user":{"login":"alexreg","id":67036,"node_id":"MDQ6VXNlcjY3MDM2","avatar_url":"https://avatars3.githubusercontent.com/u/67036?v=4","gravatar_id":"","url":"https://api.github.com/users/alexreg","html_url":"https://github.com/alexreg","followers_url":"https://api.github.com/users/alexreg/followers","following_url":"https://api.github.com/users/alexreg/following{/other_user}","gists_url":"https://api.github.com/users/alexreg/gists{/gist_id}","starred_url":"https://api.github.com/users/alexreg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alexreg/subscriptions","organizations_url":"https://api.github.com/users/alexreg/orgs","repos_url":"https://api.github.com/users/alexreg/repos","events_url":"https://api.github.com/users/alexreg/events{/privacy}","received_events_url":"https://api.github.com/users/alexreg/received_events","type":"User","site_admin":false},"body":"`, and` *","created_at":"2018-12-18T02:34:00Z","updated_at":"2018-12-18T02:39:16Z","html_url":"https://github.com/Centril/rfcs/pull/19#discussion_r242389403","pull_request_url":"https://api.github.com/repos/Centril/rfcs/pulls/19","author_association":"NONE","_links":{"self":{"href":"https://api.github.com/repos/Centril/rfcs/pulls/comments/242389403"},"html":{"href":"https://github.com/Centril/rfcs/pull/19#discussion_r242389403"},"pull_request":{"href":"https://api.github.com/repos/Centril/rfcs/pulls/19"}}},"pull_request":{"url":"https://api.github.com/repos/Centril/rfcs/pulls/19","id":239340042,"node_id":"MDExOlB1bGxSZXF1ZXN0MjM5MzQwMDQy","html_url":"https://github.com/Centril/rfcs/pull/19","diff_url":"https://github.com/Centril/rfcs/pull/19.diff","patch_url":"https://github.com/Centril/rfcs/pull/19.patch","issue_url":"https://api.github.com/repos/Centril/rfcs/issues/19","number":19,"state":"open","locked":false,"title":"[DRAFT] RFC: Default field values","user":{"login":"Centril","id":855702,"node_id":"MDQ6VXNlcjg1NTcwMg==","avatar_url":"https://avatars2.githubusercontent.com/u/855702?v=4","gravatar_id":"","url":"https://api.github.com/users/Centril","html_url":"https://github.com/Centril","followers_url":"https://api.github.com/users/Centril/followers","following_url":"https://api.github.com/users/Centril/following{/other_user}","gists_url":"https://api.github.com/users/Centril/gists{/gist_id}","starred_url":"https://api.github.com/users/Centril/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Centril/subscriptions","organizations_url":"https://api.github.com/users/Centril/orgs","repos_url":"https://api.github.com/users/Centril/repos","events_url":"https://api.github.com/users/Centril/events{/privacy}","received_events_url":"https://api.github.com/users/Centril/received_events","type":"User","site_admin":false},"body":"[Rendered](https://github.com/Centril/rfcs/blob/rfc/default-field-values/text/0000-default-field-values.md)\r\n\r\nThis is a **draft** version of an RFC for you to review, before a formal proposal is made for consideration.\r\n\r\ncc @cramertj @nrc @alexreg","created_at":"2018-12-18T01:49:12Z","updated_at":"2018-12-18T02:39:15Z","closed_at":null,"merged_at":null,"merge_commit_sha":"39804dbd7319fd7482cd4834e913444e033d97b0","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":975122043,"node_id":"MDU6TGFiZWw5NzUxMjIwNDM=","url":"https://api.github.com/repos/Centril/rfcs/labels/draft","name":"draft","color":"61359e","default":false},{"id":975121946,"node_id":"MDU6TGFiZWw5NzUxMjE5NDY=","url":"https://api.github.com/repos/Centril/rfcs/labels/rfc","name":"rfc","color":"0d6edd","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/Centril/rfcs/pulls/19/commits","review_comments_url":"https://api.github.com/repos/Centril/rfcs/pulls/19/comments","review_comment_url":"https://api.github.com/repos/Centril/rfcs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Centril/rfcs/issues/19/comments","statuses_url":"https://api.github.com/repos/Centril/rfcs/statuses/ff081b8b792bb54098c76a612c83fc9a20c2330e","head":{"label":"Centril:rfc/default-field-values","ref":"rfc/default-field-values","sha":"ff081b8b792bb54098c76a612c83fc9a20c2330e","user":{"login":"Centril","id":855702,"node_id":"MDQ6VXNlcjg1NTcwMg==","avatar_url":"https://avatars2.githubusercontent.com/u/855702?v=4","gravatar_id":"","url":"https://api.github.com/users/Centril","html_url":"https://github.com/Centril","followers_url":"https://api.github.com/users/Centril/followers","following_url":"https://api.github.com/users/Centril/following{/other_user}","gists_url":"https://api.github.com/users/Centril/gists{/gist_id}","starred_url":"https://api.github.com/users/Centril/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Centril/subscriptions","organizations_url":"https://api.github.com/users/Centril/orgs","repos_url":"https://api.github.com/users/Centril/repos","events_url":"https://api.github.com/users/Centril/events{/privacy}","received_events_url":"https://api.github.com/users/Centril/received_events","type":"User","site_admin":false},"repo":{"id":103166643,"node_id":"MDEwOlJlcG9zaXRvcnkxMDMxNjY2NDM=","name":"rfcs","full_name":"Centril/rfcs","private":false,"owner":{"login":"Centril","id":855702,"node_id":"MDQ6VXNlcjg1NTcwMg==","avatar_url":"https://avatars2.githubusercontent.com/u/855702?v=4","gravatar_id":"","url":"https://api.github.com/users/Centril","html_url":"https://github.com/Centril","followers_url":"https://api.github.com/users/Centril/followers","following_url":"https://api.github.com/users/Centril/following{/other_user}","gists_url":"https://api.github.com/users/Centril/gists{/gist_id}","starred_url":"https://api.github.com/users/Centril/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Centril/subscriptions","organizations_url":"https://api.github.com/users/Centril/orgs","repos_url":"https://api.github.com/users/Centril/repos","events_url":"https://api.github.com/users/Centril/events{/privacy}","received_events_url":"https://api.github.com/users/Centril/received_events","type":"User","site_admin":false},"html_url":"https://github.com/Centril/rfcs","description":"RFCs for changes to Rust","fork":true,"url":"https://api.github.com/repos/Centril/rfcs","forks_url":"https://api.github.com/repos/Centril/rfcs/forks","keys_url":"https://api.github.com/repos/Centril/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Centril/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Centril/rfcs/teams","hooks_url":"https://api.github.com/repos/Centril/rfcs/hooks","issue_events_url":"https://api.github.com/repos/Centril/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/Centril/rfcs/events","assignees_url":"https://api.github.com/repos/Centril/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/Centril/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/Centril/rfcs/tags","blobs_url":"https://api.github.com/repos/Centril/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Centril/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Centril/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/Centril/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Centril/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/Centril/rfcs/languages","stargazers_url":"https://api.github.com/repos/Centril/rfcs/stargazers","contributors_url":"https://api.github.com/repos/Centril/rfcs/contributors","subscribers_url":"https://api.github.com/repos/Centril/rfcs/subscribers","subscription_url":"https://api.github.com/repos/Centril/rfcs/subscription","commits_url":"https://api.github.com/repos/Centril/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/Centril/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/Centril/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/Centril/rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/Centril/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/Centril/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Centril/rfcs/merges","archive_url":"https://api.github.com/repos/Centril/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Centril/rfcs/downloads","issues_url":"https://api.github.com/repos/Centril/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/Centril/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/Centril/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/Centril/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Centril/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/Centril/rfcs/releases{/id}","deployments_url":"https://api.github.com/repos/Centril/rfcs/deployments","created_at":"2017-09-11T17:28:49Z","updated_at":"2018-11-21T04:12:12Z","pushed_at":"2018-12-18T01:49:13Z","git_url":"git://github.com/Centril/rfcs.git","ssh_url":"git@github.com:Centril/rfcs.git","clone_url":"https://github.com/Centril/rfcs.git","svn_url":"https://github.com/Centril/rfcs","homepage":"","size":6984,"stargazers_count":2,"watchers_count":2,"language":"Shell","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":4,"mirror_url":null,"archived":false,"open_issues_count":5,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":4,"open_issues":5,"watchers":2,"default_branch":"master"}},"base":{"label":"Centril:master","ref":"master","sha":"93f1627308254dffa26fc0d5f3dfceab2ab03c02","user":{"login":"Centril","id":855702,"node_id":"MDQ6VXNlcjg1NTcwMg==","avatar_url":"https://avatars2.githubusercontent.com/u/855702?v=4","gravatar_id":"","url":"https://api.github.com/users/Centril","html_url":"https://github.com/Centril","followers_url":"https://api.github.com/users/Centril/followers","following_url":"https://api.github.com/users/Centril/following{/other_user}","gists_url":"https://api.github.com/users/Centril/gists{/gist_id}","starred_url":"https://api.github.com/users/Centril/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Centril/subscriptions","organizations_url":"https://api.github.com/users/Centril/orgs","repos_url":"https://api.github.com/users/Centril/repos","events_url":"https://api.github.com/users/Centril/events{/privacy}","received_events_url":"https://api.github.com/users/Centril/received_events","type":"User","site_admin":false},"repo":{"id":103166643,"node_id":"MDEwOlJlcG9zaXRvcnkxMDMxNjY2NDM=","name":"rfcs","full_name":"Centril/rfcs","private":false,"owner":{"login":"Centril","id":855702,"node_id":"MDQ6VXNlcjg1NTcwMg==","avatar_url":"https://avatars2.githubusercontent.com/u/855702?v=4","gravatar_id":"","url":"https://api.github.com/users/Centril","html_url":"https://github.com/Centril","followers_url":"https://api.github.com/users/Centril/followers","following_url":"https://api.github.com/users/Centril/following{/other_user}","gists_url":"https://api.github.com/users/Centril/gists{/gist_id}","starred_url":"https://api.github.com/users/Centril/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Centril/subscriptions","organizations_url":"https://api.github.com/users/Centril/orgs","repos_url":"https://api.github.com/users/Centril/repos","events_url":"https://api.github.com/users/Centril/events{/privacy}","received_events_url":"https://api.github.com/users/Centril/received_events","type":"User","site_admin":false},"html_url":"https://github.com/Centril/rfcs","description":"RFCs for changes to Rust","fork":true,"url":"https://api.github.com/repos/Centril/rfcs","forks_url":"https://api.github.com/repos/Centril/rfcs/forks","keys_url":"https://api.github.com/repos/Centril/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Centril/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Centril/rfcs/teams","hooks_url":"https://api.github.com/repos/Centril/rfcs/hooks","issue_events_url":"https://api.github.com/repos/Centril/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/Centril/rfcs/events","assignees_url":"https://api.github.com/repos/Centril/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/Centril/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/Centril/rfcs/tags","blobs_url":"https://api.github.com/repos/Centril/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Centril/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Centril/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/Centril/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Centril/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/Centril/rfcs/languages","stargazers_url":"https://api.github.com/repos/Centril/rfcs/stargazers","contributors_url":"https://api.github.com/repos/Centril/rfcs/contributors","subscribers_url":"https://api.github.com/repos/Centril/rfcs/subscribers","subscription_url":"https://api.github.com/repos/Centril/rfcs/subscription","commits_url":"https://api.github.com/repos/Centril/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/Centril/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/Centril/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/Centril/rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/Centril/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/Centril/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Centril/rfcs/merges","archive_url":"https://api.github.com/repos/Centril/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Centril/rfcs/downloads","issues_url":"https://api.github.com/repos/Centril/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/Centril/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/Centril/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/Centril/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Centril/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/Centril/rfcs/releases{/id}","deployments_url":"https://api.github.com/repos/Centril/rfcs/deployments","created_at":"2017-09-11T17:28:49Z","updated_at":"2018-11-21T04:12:12Z","pushed_at":"2018-12-18T01:49:13Z","git_url":"git://github.com/Centril/rfcs.git","ssh_url":"git@github.com:Centril/rfcs.git","clone_url":"https://github.com/Centril/rfcs.git","svn_url":"https://github.com/Centril/rfcs","homepage":"","size":6984,"stargazers_count":2,"watchers_count":2,"language":"Shell","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":4,"mirror_url":null,"archived":false,"open_issues_count":5,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":4,"open_issues":5,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Centril/rfcs/pulls/19"},"html":{"href":"https://github.com/Centril/rfcs/pull/19"},"issue":{"href":"https://api.github.com/repos/Centril/rfcs/issues/19"},"comments":{"href":"https://api.github.com/repos/Centril/rfcs/issues/19/comments"},"review_comments":{"href":"https://api.github.com/repos/Centril/rfcs/pulls/19/comments"},"review_comment":{"href":"https://api.github.com/repos/Centril/rfcs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Centril/rfcs/pulls/19/commits"},"statuses":{"href":"https://api.github.com/repos/Centril/rfcs/statuses/ff081b8b792bb54098c76a612c83fc9a20c2330e"}},"author_association":"OWNER"}}
{"actor":{"display_login":"alexreg"}}