{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/6739","repository_url":"https://api.github.com/repos/dotnet/roslyn","labels_url":"https://api.github.com/repos/dotnet/roslyn/issues/6739/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/roslyn/issues/6739/comments","events_url":"https://api.github.com/repos/dotnet/roslyn/issues/6739/events","html_url":"https://github.com/dotnet/roslyn/issues/6739","id":116634590,"number":6739,"title":"Proposal: Record Enum Types","user":{"login":"alrz","id":3105979,"avatar_url":"https://avatars.githubusercontent.com/u/3105979?v=3","gravatar_id":"","url":"https://api.github.com/users/alrz","html_url":"https://github.com/alrz","followers_url":"https://api.github.com/users/alrz/followers","following_url":"https://api.github.com/users/alrz/following{/other_user}","gists_url":"https://api.github.com/users/alrz/gists{/gist_id}","starred_url":"https://api.github.com/users/alrz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alrz/subscriptions","organizations_url":"https://api.github.com/users/alrz/orgs","repos_url":"https://api.github.com/users/alrz/repos","events_url":"https://api.github.com/users/alrz/events{/privacy}","received_events_url":"https://api.github.com/users/alrz/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/dotnet/roslyn/labels/2%20-%20Ready","name":"2 - Ready","color":"CCCCCC"},{"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"}],"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":null,"comments":85,"created_at":"2015-11-12T20:36:09Z","updated_at":"2016-02-20T19:19:09Z","closed_at":null,"body":"## Record Enum Types\r\n\r\nCurrently, `enum` types would be considered as complete patterns but they don't have any \"record\" syntax to be used in pattern matching. This proposal tries to fill this gap.\r\n\r\nThis proposal won't affect regular `enum` types like #3704, rather, it suggests an `enum`-like syntax for declaring flat hierarchies of ADTs (with both value and reference types).\r\n\r\n### Enum structs\r\n\r\n*Enum structs* would be more like Java enum types, for example\r\n\r\n```cs\r\npublic enum struct Color(int R, int G, int B) {\r\n\tBlue(0,0,255),\r\n\tGreen(0,255,0),\r\n\tRed(255,0,0)\r\n}\r\n```\r\nwould translate to\r\n```cs\r\npublic struct Color {\r\n\tpublic readonly static Color Blue = new Color(0, 0, 255);\r\n\tpublic readonly static Color Green = new Color(0, 255, 0);\r\n\tpublic readonly static Color Red = new Color(255, 0, 0);\r\n\t\r\n\tprivate Color(int R, int G, int B) {\r\n\t    this.R = R;\r\n\t    this.G = G;\r\n\t    this.B = B;\r\n\t}\r\n\r\n\tpublic int R { get; }\r\n\tpublic int G { get; }\r\n\tpublic int B { get; }\r\n}\r\n```\r\nAnother example from Java docs:\r\n```cs\r\npublic enum struct Planet(double Mass, double Radius) {\r\n    Mercury (3.303e+23, 2.4397e6),\r\n    Venus   (4.869e+24, 6.0518e6),\r\n    Earth   (5.976e+24, 6.37814e6),\r\n    Mars    (6.421e+23, 3.3972e6),\r\n    Jupiter (1.9e+27,   7.1492e7),\r\n    Saturn  (5.688e+26, 6.0268e7),\r\n    Uranus  (8.686e+25, 2.5559e7),\r\n    Neptune (1.024e+26, 2.4746e7),\r\n    Pluto   (1.27e+22,  1.137e6);\r\n   \r\n    public const double G = 6.67300E-11;\r\n\r\n    public double SurfaceGravity =>\r\n        G * Mass / (Radius * Radius);\r\n    \r\n    public double SurfaceWeight(double otherMass) =>\r\n        otherMass * SurfaceGravity;\r\n}\r\n```\r\n\r\nThis struct must not be instantiable, because of the completeness of the pattern.\r\n\r\n### Enum classes\r\n\r\n*Enum classes* are useful for declaring **flat** hierarchy of ADTs (similar to F# discriminated unions). For example. the following\r\n```cs\r\npublic sealed abstract class Option<T> {\r\n\tpublic sealed class Some(T Value) : Option<T>;\r\n\tpublic sealed class None() : Option<T>;\r\n}\r\n```\r\ncould be written as\r\n```cs\r\npublic enum class Option<T> {\r\n\tSome(T value : Value),\r\n\tNone;\r\n}\r\n```\r\nWith enum classes, `abstract sealed` would be considered as an advanced feature where you can declare more complicated ADTs.\r\n\r\n#### Remarks\r\n- Each member translates to a subclass of the `Option<T>` in this example.\r\n- Enum classes are implicitly `abstract` ~~and cannot extend any other types~~.\r\n- Enum class members can have a body to potentially override methods on the base (like Java).\r\n\r\n```cs\r\npublic enum class Expr {\r\n  Const(double Value)        { public override string ToString() => Value.ToString(); },\r\n  Mul(Expr Left, Expr Right) { public override string ToString() => $\"({Left} * {Right})\"; },\r\n  Add(Expr Left, Expr Right) { public override string ToString() => $\"({Left} + {Right})\"; },\r\n  Div(Expr Left, Expr Right) { public override string ToString() => $\"({Left} / {Right})\"; },\r\n  Sub(Expr Left, Expr Right) { public override string ToString() => $\"({Left} - {Right})\"; },\r\n}\r\n```\r\n\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/comments/186668386","html_url":"https://github.com/dotnet/roslyn/issues/6739#issuecomment-186668386","issue_url":"https://api.github.com/repos/dotnet/roslyn/issues/6739","id":186668386,"user":{"login":"alrz","id":3105979,"avatar_url":"https://avatars.githubusercontent.com/u/3105979?v=3","gravatar_id":"","url":"https://api.github.com/users/alrz","html_url":"https://github.com/alrz","followers_url":"https://api.github.com/users/alrz/followers","following_url":"https://api.github.com/users/alrz/following{/other_user}","gists_url":"https://api.github.com/users/alrz/gists{/gist_id}","starred_url":"https://api.github.com/users/alrz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alrz/subscriptions","organizations_url":"https://api.github.com/users/alrz/orgs","repos_url":"https://api.github.com/users/alrz/repos","events_url":"https://api.github.com/users/alrz/events{/privacy}","received_events_url":"https://api.github.com/users/alrz/received_events","type":"User","site_admin":false},"created_at":"2016-02-20T19:19:09Z","updated_at":"2016-02-20T19:19:09Z","body":"A hypothetical expansion for `enum class` for the following hierarchy,\r\n```\r\nroot\r\n| case1\r\n| case2\r\n| case3\r\n  | case4\r\n  | case5\r\n```\r\n```cs\r\nenum class Root { Case1(object), Case2 }\r\nenum class Case3 : Root { Case4, Case5 }\r\n```\r\n```cs\r\nabstract class Root {\r\n  // allow enums to inherit from each other\r\n  private protected Root() { }\r\n  // helper methods (probably better be abstract)\r\n  public virtual bool IsCase1 { get; } = false;\r\n  public virtual bool IsCase2 { get; } = false;\r\n  public virtual bool IsCase3 { get; } = false;\r\n  public virtual bool IsCase4 { get; } = false;\r\n  public virtual bool IsCase5 { get; } = false;\r\n  public abstract Tags Tag { get; }\r\n  public sealed class Case1 : Root {\r\n    public override bool IsCase1 => true;\r\n    public override Tags Tag => Tags.Case1;\r\n    // unnamed members produce ItemX names\r\n    // either all or none of the members should be named\r\n    public object Item1 { get; }\r\n    // record expansion follows ... \r\n  }\r\n  public sealed class Case2 : Root {\r\n    public override bool IsCase2 => true;\r\n    public override Tags Tag => Tags.Case2;\r\n    // additional optimization for 'empty sealed records'\r\n    // we can redirect 'type invocation' to this member\r\n    public static readonly Case2 Instance = new Case2();\r\n    // record expansion follows ... \r\n  }\r\n  // can be a static class with const fields\r\n  public enum Tags { Case1, Case2, Case3, Case4, Case5 }\r\n  // abstract record expansion follows ...\r\n}\r\nabstract class Case3 : Root {\r\n  private protected Case3() { }\r\n  public override bool IsCase3 => true;\r\n  public override Tags Tag => Tags.Case3;\r\n  public sealed class Case4 : Case3 {\r\n    public override bool IsCase4 => true;\r\n    public override Tags Tag => Tags.Case4;\r\n    // record expansion follows ... \r\n  }\r\n  public sealed class Case5 : Case3 {\r\n    public override bool IsCase5 => true;\r\n    public override Tags Tag => Tags.Case5;\r\n    // record expansion follows ... \r\n  }\r\n  // abstract record expansion follows ...\r\n}\r\n```\r\n`enum class` inheritance depends on abstract records if they ever made it."}}