{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/5172","labels_url":"https://api.github.com/repos/dotnet/roslyn/issues/5172/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/roslyn/issues/5172/comments","events_url":"https://api.github.com/repos/dotnet/roslyn/issues/5172/events","html_url":"https://github.com/dotnet/roslyn/issues/5172","id":106071070,"number":5172,"title":"[Proposal] \"with\" expressions for record types","user":{"login":"gafter","id":3804346,"avatar_url":"https://avatars.githubusercontent.com/u/3804346?v=3","gravatar_id":"","url":"https://api.github.com/users/gafter","html_url":"https://github.com/gafter","followers_url":"https://api.github.com/users/gafter/followers","following_url":"https://api.github.com/users/gafter/following{/other_user}","gists_url":"https://api.github.com/users/gafter/gists{/gist_id}","starred_url":"https://api.github.com/users/gafter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gafter/subscriptions","organizations_url":"https://api.github.com/users/gafter/orgs","repos_url":"https://api.github.com/users/gafter/repos","events_url":"https://api.github.com/users/gafter/events{/privacy}","received_events_url":"https://api.github.com/users/gafter/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/dotnet/roslyn/labels/Area-Language%20Design","name":"Area-Language Design","color":"5319e7"},{"url":"https://api.github.com/repos/dotnet/roslyn/labels/Feature%20Request","name":"Feature Request","color":"fc2929"},{"url":"https://api.github.com/repos/dotnet/roslyn/labels/Feature%20Specification","name":"Feature Specification","color":"fc2929"}],"state":"open","locked":false,"assignee":{"login":"gafter","id":3804346,"avatar_url":"https://avatars.githubusercontent.com/u/3804346?v=3","gravatar_id":"","url":"https://api.github.com/users/gafter","html_url":"https://github.com/gafter","followers_url":"https://api.github.com/users/gafter/followers","following_url":"https://api.github.com/users/gafter/following{/other_user}","gists_url":"https://api.github.com/users/gafter/gists{/gist_id}","starred_url":"https://api.github.com/users/gafter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gafter/subscriptions","organizations_url":"https://api.github.com/users/gafter/orgs","repos_url":"https://api.github.com/users/gafter/repos","events_url":"https://api.github.com/users/gafter/events{/privacy}","received_events_url":"https://api.github.com/users/gafter/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/dotnet/roslyn/milestones/8","html_url":"https://github.com/dotnet/roslyn/milestones/C%23%207%20and%20VB%2015","labels_url":"https://api.github.com/repos/dotnet/roslyn/milestones/8/labels","id":962632,"number":8,"title":"C# 7 and VB 15","description":"\r\n\r\n<!---\r\n@huboard:{\"order\":0.375}\r\n-->\r\n","creator":{"login":"gafter","id":3804346,"avatar_url":"https://avatars.githubusercontent.com/u/3804346?v=3","gravatar_id":"","url":"https://api.github.com/users/gafter","html_url":"https://github.com/gafter","followers_url":"https://api.github.com/users/gafter/followers","following_url":"https://api.github.com/users/gafter/following{/other_user}","gists_url":"https://api.github.com/users/gafter/gists{/gist_id}","starred_url":"https://api.github.com/users/gafter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gafter/subscriptions","organizations_url":"https://api.github.com/users/gafter/orgs","repos_url":"https://api.github.com/users/gafter/repos","events_url":"https://api.github.com/users/gafter/events{/privacy}","received_events_url":"https://api.github.com/users/gafter/received_events","type":"User","site_admin":false},"open_issues":56,"closed_issues":10,"state":"open","created_at":"2015-02-02T23:41:34Z","updated_at":"2015-10-07T20:23:58Z","due_on":null,"closed_at":null},"comments":32,"created_at":"2015-09-11T18:56:16Z","updated_at":"2015-10-14T02:36:33Z","closed_at":null,"body":"This is a proposed enhancement to the proposal for *records* in #206.\r\n\r\nA new expression form is proposed:\r\n\r\n> *primary-expression*:\r\n> &nbsp;&nbsp;&nbsp;&nbsp;*with-expression*:\r\n> *with-expression*:\r\n> &nbsp;&nbsp;&nbsp;&nbsp;*primary-expression* `with` `{` *with-initializer-list* `}`\r\n> *with-initializer-list*:\r\n> &nbsp;&nbsp;&nbsp;&nbsp;*with-initializer*\r\n> &nbsp;&nbsp;&nbsp;&nbsp;*with-initializer* `,` *with-initializer-list*\r\n> *with-initializer*:\r\n> &nbsp;&nbsp;&nbsp;&nbsp;*identifier* `=` *expression*\r\n\r\nThe token `with` is a new context-sensitive keyword.\r\n\r\n### Semantics\r\n\r\nThe *with-expression* is translated into a factory invocation that copies members from the *primary-expression* on the left-hand-side into factory's parameters, but with some of those replaced by values from the initializer list.\r\n\r\nA record type declaration shall cause the addition of a compiler-defined method that facilitates this. It is a `public virtual` method that returns the containing type, whose name is `With`, and that has parameters corresponding to the primary constructor's parameters.\r\n\r\n(This needs to be described in more detail, including specifying that the left-hand-side expression is evaluated once, the constraints on its type, that identifiers in a *with-intiializer* bind to a property (or field) of the type, and that the correspondence between constructor parameters and properties are used according to the spec for *records*. Similarly it needs to give definite assignment rules, order of evaluation, etc.)\r\n\r\n### Example:\r\n\r\n```cs\r\nclass Person(string FirstName, string LastName);\r\n...\r\n    Person p = new Person(FirstName: \"Neil\", LastName: \"Gafter\");\r\n    Person q = p with { FirstName = \"Neal\" };\r\n```\r\n\r\nThe latter is translated into\r\n\r\n```cs\r\n    Person q = p.With(FirstName: \"Neal\", LastName: p.LastName);\r\n```\r\n\r\nTo be clear, the `Person` declaration's expansion includes the following:\r\n\r\n```cs\r\nclass Person\r\n{\r\n    public string FirstName { get; }\r\n    public string LastName { get; }\r\n    public Person(string FirstName, string LastName)\r\n        { this.FirstName = FirstName; this.LastName = LastName; }\r\n    public virtual Person With(string FirstName, string LastName)\r\n        { return new Person(FirstName, LastName); }\r\n    // as well as other members not relevant to this issue\r\n}\r\n```\r\n\r\nThe reason for the `public virtual With` method is to facilitate inheritance; a derived class\r\n\r\n```cs\r\nclass Student(string FirstName, string LastName, int Grade) : Person(FirstName, LastName);\r\n```\r\n\r\nwould include, in its expansion\r\n\r\n```cs\r\n    public override Person With(string FirstName, string LastName)\r\n        { return new Student(FirstName, LastName, this.Grade); }\r\n```\r\n\r\nBecause the semantics of this new expression form require a language-defined mapping between constructor arguments and properties of the type, and a *primary* constructor, it is only defined for record types as specified in #206. Expanding this construct to other types may be the subject of a separate proposal.\r\n"},"comment":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/comments/147906839","html_url":"https://github.com/dotnet/roslyn/issues/5172#issuecomment-147906839","issue_url":"https://api.github.com/repos/dotnet/roslyn/issues/5172","id":147906839,"user":{"login":"gafter","id":3804346,"avatar_url":"https://avatars.githubusercontent.com/u/3804346?v=3","gravatar_id":"","url":"https://api.github.com/users/gafter","html_url":"https://github.com/gafter","followers_url":"https://api.github.com/users/gafter/followers","following_url":"https://api.github.com/users/gafter/following{/other_user}","gists_url":"https://api.github.com/users/gafter/gists{/gist_id}","starred_url":"https://api.github.com/users/gafter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gafter/subscriptions","organizations_url":"https://api.github.com/users/gafter/orgs","repos_url":"https://api.github.com/users/gafter/repos","events_url":"https://api.github.com/users/gafter/events{/privacy}","received_events_url":"https://api.github.com/users/gafter/received_events","type":"User","site_admin":false},"created_at":"2015-10-14T02:36:33Z","updated_at":"2015-10-14T02:36:33Z","body":"It isn’t clear that the compiler has enough information to implement `With` methods in the face of inheritance. For example, given:\r\n\r\n```cs\r\nclass Rectangle(int Width, int Height);\r\n```\r\n\r\nwhich has the compiler-generated method\r\n\r\n```cs\r\npublic virtual Rectangle With((int Width, int Height) => new Rectangle(Width, Height);\r\n```\r\n\r\nand the derived class\r\n\r\n```cs\r\nclass Square(int Side) : Rectangle(Side, Side);\r\n```\r\n\r\nHow would the compiler implement the override of `Rectangle.With` in the class `Square`?\r\n\r\nI think one reasonable policy is to require the `With` methods in record types, and by default the compiler provides non-virtual implementations. But users may provide their own implementations, which in some cases might be virtual.\r\n"}}