# C# Language Design Notes for Apr 30, 2018 ***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!*** # Switch expressions Current syntax: ``` c# e switch { 1 => "one", 2 => "two", var x when x > 2 => "too many", _ => "too few" } ``` No `default` - instead use `_`. If the compiler thinks there are cases you don't handle, it'll warn. If you actually don't handle a case we throw an exception (NRE for prototype, something else in the long run). Also discussed: - use `match` instead of `switch` - keyword first, followed by parens, like `switch` statement - or without parens - optional implicit default at the end? The current thing is nice for error recovery. The lack of statements inside may be a frustration, but that's orthogonal. Let's leave it for now. ## Exploration Is there a way to instead generalize the syntax from the conditional (ternary) operator? After all, semantically speaking this could be viewed as a general form: Conditional operators and switch expressions on bool are semantically equivalent. ``` c# e ? true => e1 : false => e2 ``` The fact that you know the number of colons today means you can have fewer parentheses than you would get away with here. ``` c# e ? true => e1 ? x : y : false => e2 ``` It's not in fact obvious whether there should be many `?`s and one `:`, or one `?` and many `:`s: ``` c# // Interpret ? as following the tested expression, and : as a separator of test/result pairs e ? 1 => "one" : 2 => "two" : var x when x > 2 => "too many" : _ => "too few" // Interpret ? as introducing test/result pairs, and : as introducing the fallback result e ? 1 => "one" ? 2 => "two" ? var x when x > 2 => "too many" : "too few" ``` The `=>` glyph is probably not right in a `?:` style syntax. It would have to be something else that more clearly signals pattern/result pairs. ``` c# e ? 1 -> "one" ? 2 -> "two" ? var x when x > 2 -> "too many" : "too few" ``` ## Considering our options ``` c# // Compromise - terser e ? { 1: "one", 2: "two", var x when x > 2: "two many", "too few" } // Formatted e ? { 1: "one", 2: "two", var x when x > 2: "two many", "too few" } e switch { 1: "one", 2: "two", var x when x > 2: "two many", "too few" } // Some of these in context of a var var x = e ? 1 -> "one" : 2 -> "two" : var x when x > 2 -> "too many" : _ -> "too few"; var x = e ? { 1: "one", 2: "two", var x when x > 2: "two many", "too few" }; var x = e switch { 1: "one", 2: "two", var x when x > 2: "two many", "too few" }; // Some of these as one-liners in a method call M(x switch { null => 0, _ => x.Length }); // 1 M(x switch { null: 0, x.Length }); // 2 M(x ? null -> 0 : _ -> x.Length); // 3 M(x ? { null: 0, x.Length }); // 4 M(x ? null -> 0 : x.Length); // 5 M(x ? { null -> 0, x.Length }); // 6 ``` Argument against 1: ``` c# strings.Select(x => x switch { null => 0, _ => x.Length }); // Lots of => with different meaning ``` Argument against `->`: Has meaning in unsafe code Argument against `:` as used in 4: Clashes with other uses of `:`. Where input is an expression rather than a variable: ``` c# M(e switch { null => 0, var x => x.Length }); // 1 - 0 M(e switch { null: 0, var x: x.Length }); // 2 - 13 - 6 M(e ? null -> 0 : var x -> x.Length); // 3 - 1 M(e ? { null: 0, var x: x.Length }); // 4 - 6 - 3 M(e ? { null -> 0, var x -> x.Length }); // 6 - 0 ``` We might want to allow the last thing to be a default value without pattern, but not in the prototype. ## Conclusion The prototype will have version 2. We're saving for later whether the last clause should be able to leave off a pattern. # Property pattern ``` c# if (e is { Name: "Mads", Employer: { ID: string id } }) { WriteLine(id); } // 1 - Current if (e is { Name = "Mads", Employer = { ID = string id } }) { WriteLine(id); } // 2 if (e is { Name == "Mads", Employer == { ID == string id } }) { WriteLine(id); } // 3 if (e is { Name is "Mads", Employer is { ID is string id } }) { WriteLine(id); } // 4 ``` 1 is what we have implemented, but it clashes a little with what we just decided for switch expressions. 2 mirrors object initializers the most 3 implies equality, but clashes in meaning with `==` elsewhere 4 emphasizes `is` as a means for applying patterns ``` c# var result = person switch { { Name: "Mads", Employer: { ID: string id } }: id, (_, id: var pid){ Name: "Matt" }: pid, _: null }; ``` There's a clash but maybe it doesn't feel too bad. The second pattern with three different meanings of `:` is certainly not common. ``` c# var result = person switch { { Name is "Mads", Employer is { ID is string id } }: id, (_, var pid){ Name is "Matt" }: pid, _: null }; ``` ## Conclusion Decision: stay with `:` for prototype, remains open question though!