www.digitalmars.com         C & C++   DMDScript  

digitalmars.dip.ideas - Improvements to switch

reply ryuukk_ <ryuukk.dev gmail.com> writes:
It is time to make them nice to use


- allow them as expression

```D
int myvalue = switch(code) {
     // ...
};

```

- more concise

```D
switch(code) {
     case 1 -> "what";
     case 2, 3 -> "ok";
     else -> "no";
}
```

- pattern match

```D
switch(tagged) {
     case A, B -> do_that();
     case C myc -> do_this(myc);
     else -> nothing();
}
```
Apr 16
next sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Tuesday, 16 April 2024 at 10:34:21 UTC, ryuukk_ wrote:
 It is time to make them nice to use


 - allow them as expression

 ```D
 int myvalue = switch(code) {
     // ...
 };

 ```
About this, the main point is rather ```d /*-->*/ const /*<--*/ int myvalue = switch(code) { // ... }; ``` "ah finally you can define a const var decl that relies on branching" (without using the conditional expression...) Then there's something you must think about, that's the fallback, i.e the default clause. If you use the default clause to error you're lucky because D has noreturn now.
Apr 16
parent reply IchorDev <zxinsworld gmail.com> writes:
On Tuesday, 16 April 2024 at 16:00:48 UTC, Basile B. wrote:
 About this, the main point is rather

 ```d
 /*-->*/ const /*<--*/ int myvalue = switch(code) {
     // ...
 };
 ```

 "ah finally you can define a const var decl that relies on 
 branching" (without using the conditional expression...)
You can already do that. ```d const string myValue = (){ switch(code){ case 1: return "what"; case 2, 3: return "ok"; default: return "no"; } }();
Apr 27
next sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Saturday, 27 April 2024 at 14:58:19 UTC, IchorDev wrote:
 On Tuesday, 16 April 2024 at 16:00:48 UTC, Basile B. wrote:
 About this, the main point is rather

 ```d
 /*-->*/ const /*<--*/ int myvalue = switch(code) {
     // ...
 };
 ```

 "ah finally you can define a const var decl that relies on 
 branching" (without using the conditional expression...)
You can already do that. ```d const string myValue = (){ switch(code){ case 1: return "what"; case 2, 3: return "ok"; default: return "no"; } }();
Sure but the matching AST is unnecessarily complex. A function literal, plenty of return statements, at least 1 capture. Consequently the path borrowed by the compiler is much more complex, it has to do things that would not be done with the expression: return type inference, block exits, etc. Then without optimizations enabled that does not have the equivalent runtime performances.
Apr 27
parent =?UTF-8?B?Q2hsb8Op?= <chloekek use.startmail.com> writes:
On 4/28/24 01:58, Basile B. wrote:
 On Saturday, 27 April 2024 at 14:58:19 UTC, IchorDev wrote:
 On Tuesday, 16 April 2024 at 16:00:48 UTC, Basile B. wrote:
 About this, the main point is rather

 ```d
 /*-->*/ const /*<--*/ int myvalue = switch(code) {
     // ...
 };
 ```

 "ah finally you can define a const var decl that relies on branching" 
 (without using the conditional expression...)
You can already do that. ```d const string myValue = (){     switch(code){         case 1:    return "what";         case 2, 3: return "ok";         default:   return "no";     } }();
Sure but the matching AST is unnecessarily complex. A function literal, plenty of return statements, at least 1 capture. Consequently the path borrowed by the compiler is much more complex, it has to do things that would not be done with the expression: return type inference, block exits, etc. Then without optimizations enabled that does not have the equivalent runtime performances.
Specifically promoting switch to an expression would be a wasted opportunity to generalize this to other types of statements, such as try statements. Here are some examples in pseudo-D of how that could be useful. In these examples, a hypothetical do keyword could prefix any statement and turn it into an expression, and a yield statement would provide the result of evaluating that expression: // no need to (default-)initialize file first auto file = do try { yield open(path); } catch (ErrnoException ex) { if (ex.errno == ENOENT) return; // return from caller throw ex; }; // use file without catching ErrnoException file.write("hello"); Or foreach statements: const value = do { foreach (item; someOpApplyStruct) if (f(item)) yield item; throw new NotFoundError; }; If the do-ed statement would run off the end (as with a non-void function lacking a return statement) that would be an error. Besides initializing variables, another advantage of promoting statements to expressions directly instead of through a called lambda is that you can have control flow out of the expression into another statement, such as by break, continue, or return statements.
Apr 28
prev sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Saturday, 27 April 2024 at 14:58:19 UTC, IchorDev wrote:
 On Tuesday, 16 April 2024 at 16:00:48 UTC, Basile B. wrote:
 About this, the main point is rather

 ```d
 /*-->*/ const /*<--*/ int myvalue = switch(code) {
     // ...
 };
 ```

 "ah finally you can define a const var decl that relies on 
 branching" (without using the conditional expression...)
You can already do that. ```d const string myValue = (){ switch(code){ case 1: return "what"; case 2, 3: return "ok"; default: return "no"; } }();
Besides the problems exposed in the first answer (essentially: "it's a workaround") I've found a case where this does not work. It's about selecting an lvalue with a switch: ```d void main() { int a,b,c,d,cond; auto ref () { switch (cond) { case 1: return a; case 2: return b; case 3: return c; default: return d; } }() = 0; } ``` see https://issues.dlang.org/show_bug.cgi?id=24525 The switchexp would have the same problem: the parser sees "switch" then it branches on statement parsing. Statement parsing sees "switch", then it branches on SwitchStmt parsing. Not so dramatic but the lambda solution is 1. a workaround, 2. not perfect. For that case you have 1. to explain the lambda trick 2. why you have to put the lambda between parens. With the switch expr, you just have to explain point 2.
Apr 30
parent Nick Treleaven <nick geany.org> writes:
On Tuesday, 30 April 2024 at 13:15:45 UTC, Basile B. wrote:
 see https://issues.dlang.org/show_bug.cgi?id=24525
There's now a fix for that.
 The switchexp would have the same problem: the parser sees 
 "switch" then it branches on statement parsing.
That's why the syntax should be designed to be easily distinguishable by the parser.
May 01
prev sibling next sibling parent reply Meta <jared771 gmail.com> writes:
On Tuesday, 16 April 2024 at 10:34:21 UTC, ryuukk_ wrote:
 It is time to make them nice to use


 - allow them as expression

 ```D
 int myvalue = switch(code) {
     // ...
 };

 ```

 - more concise

 ```D
 switch(code) {
     case 1 -> "what";
     case 2, 3 -> "ok";
     else -> "no";
 }
 ```

 - pattern match

 ```D
 switch(tagged) {
     case A, B -> do_that();
     case C myc -> do_this(myc);
     else -> nothing();
 }
 ```
A couple more things: - branch guards ```D auto input = readln().strip().to!int(); auto s = switch (input) { case n if (n == 0) -> "zero"; case n if (n > 0) -> "greater than zero"; case n if (n < 0) -> "less than zero"; }; switch (readln().strip()) { case string: "" -> writeln("empty string"); // Naming the value is optional case string s: "asdf" -> writeln(s[2..$]); // Prints "df" } ``` - pattern match on arrays, slices: ```D int[3] staticArr = [1, 2, 3]; switch (staticArr) { case int[N], size_t N -> writeln("Static int array of size ", N); case int[N], size_t N: 1 -> writeln("This branch won't be taken"); case int[N], size_t N if (N == 1) -> writeln("Equivalent to previous branch"); case int[2] -> writeln("This branch won't be taken either"); case string[N], N -> writeln("Nope"); } string[] slice = ["D", "rocks", "!"]; switch (slice) { case string[] : [] -> writeln("empty slice"); case string[] s: ["D"] -> writln(s[0]); case string[] s: ["D", rest...] -> writeln(rest); // Prints ["rocks", "!"] case string[] s: ["D", mid..., "!"] -> writeln(mid); // Prints "rocks" case string[] s: ["D", "rocks", "!"] -> writeln(s); // Prints ["D", "rocks", "!"] } ``` It'd be really nice to be able to pattern match on ranges as well, but I don't know exactly how we'd do that given how they work.
Apr 16
next sibling parent Nick Treleaven <nick geany.org> writes:
On Tuesday, 16 April 2024 at 18:25:45 UTC, Meta wrote:
     case string: "" -> writeln("empty string"); // Naming the 
 value is optional
Presumably we could leave off the type: ```d case : "" -> writeln("empty string"); ``` Though we might want to require an identifier or `_` when there is a type. So we'd have this grammar: ``` Case: case Pattern -> Statement case Type? Identifier Pattern? -> Statement Pattern: `:` AssignExpression `if` `(` AssignExpression `)` ```
 int[3] staticArr = [1, 2, 3];
 switch (staticArr) {
    case int[N], size_t N -> writeln("Static int array of size 
 ", N);
Could have type inference too, like for template parameter inference. ```d case T[N] _, T, alias N -> writeln("Static ", T.stringof, " array of size ", N); ``` Inferred symbols would be listed after matching values.
     case string[] s: ["D", rest...] -> writeln(rest);     // 
 Prints ["rocks", "!"]
So `rest` would be typed `string[]`.
     case string[] s: ["D", mid..., "!"]  -> writeln(mid); // 
 Prints "rocks"
I think `mid` cannot be variadic in order for it to be typed `string`. So it would be: ```d case string[] s: ["D", mid, "!"] -> writeln(mid); // Prints "rocks" ```
Apr 17
prev sibling parent reply Nick Treleaven <nick geany.org> writes:
On Tuesday, 16 April 2024 at 18:25:45 UTC, Meta wrote:
 - branch guards
 - pattern match on arrays, slices:
Some other things, based on section 3.3 of this C++ proposal: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2392r2.pdf - Multiple alternatives that have the same result: || E.g. ```d case :9 || :15 -> "not prime"; ``` - Multiple constraints required for a result: && E.g. ```d switch (variant) { case int _ && :42 -> "int and 42"; ``` - Grouping common names and constraints: { } E.g. ```d switch (variant) { case int i { case if (i < 0) -> "negative int"; default -> "some other int"; } ```
Apr 17
next sibling parent reply Meta <jared771 gmail.com> writes:
On Wednesday, 17 April 2024 at 11:24:16 UTC, Nick Treleaven wrote:
 On Tuesday, 16 April 2024 at 18:25:45 UTC, Meta wrote:
 - branch guards
 - pattern match on arrays, slices:
Some other things, based on section 3.3 of this C++ proposal: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2392r2.pdf - Multiple alternatives that have the same result: || E.g. ```d case :9 || :15 -> "not prime"; ```
This is already covered by regular switch statements. You can write: ```D case 9, 15 -> "not prime"; ```
 - Multiple constraints required for a result: &&

 E.g.
 ```d
 switch (variant) {
     case int _ && :42 -> "int and 42";
 ```
I think this would require some sort of `opMatch` function to allow custom unpacking of arbitrary structs/classes. Ideally it would allow you to do: ```D switch (variant) { case int n if (n == 42) -> "int and 42"; // Or alternatively case int n: 42 -> "int and 42"; } ```
 - Grouping common names and constraints: { }

 E.g.
 ```d
 switch (variant) {
     case int i {
         case if (i < 0) -> "negative int";
         default -> "some other int";
     }
 ```
```D switch (variant) { // goto default is already a feature of regular switch statements case int i -> i < 0 ? "negative int" : goto default; default -> "some other int"; } ``` This will work _if_ `goto default` is typed as `noreturn`. I doubt that's the case, but that's something that can also be fixed in the compiler.
Apr 18
parent reply Nick Treleaven <nick geany.org> writes:
On Friday, 19 April 2024 at 06:28:55 UTC, Meta wrote:
 On Wednesday, 17 April 2024 at 11:24:16 UTC, Nick Treleaven 
 wrote:
 On Tuesday, 16 April 2024 at 18:25:45 UTC, Meta wrote:
 - branch guards
 - pattern match on arrays, slices:
Some other things, based on section 3.3 of this C++ proposal: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2392r2.pdf - Multiple alternatives that have the same result: || E.g. ```d case :9 || :15 -> "not prime"; ```
This is already covered by regular switch statements. You can write: ```D case 9, 15 -> "not prime"; ```
It would be ambiguous to write e.g. `case name if (cond) ->` - is it matching a value `name`, or is `name` naming the switch variable? But the grammar was me trying to extrapolate from your examples, and it might not be workable for that to be compatible with today's switch statement. Perhaps it's better to not reuse `switch` because we will want pattern matching with multiple statement branches, we won't always want `switch` to be an expression.
 - Multiple constraints required for a result: &&

 E.g.
 ```d
 switch (variant) {
     case int _ && :42 -> "int and 42";
 ```
I think this would require some sort of `opMatch` function to allow custom unpacking of arbitrary structs/classes. Ideally it would allow you to do: ```D switch (variant) { case int n if (n == 42) -> "int and 42"; // Or alternatively case int n: 42 -> "int and 42"; } ```
Yes. In the C++ paper it's `operator is` IIRC.
 - Grouping common names and constraints: { }

 E.g.
 ```d
 switch (variant) {
     case int i {
         case if (i < 0) -> "negative int";
         default -> "some other int";
     }
 ```
```D switch (variant) { // goto default is already a feature of regular switch statements case int i -> i < 0 ? "negative int" : goto default; default -> "some other int"; } ``` This will work _if_ `goto default` is typed as `noreturn`. I doubt that's the case, but that's something that can also be fixed in the compiler.
BTW that's not what my example does - the `i < 0` is part of the matching, not part of the result. The difference is there can be other `case` statements under the first one. `case if (i < 0) ->` would try the next case statement when i >= 0 rather than jumping to the default case. Also for your example I don't understand why `goto default` wouldn't have the same type as the result for the `default` branch.
Apr 19
parent reply Meta <jared771 gmail.com> writes:
On Friday, 19 April 2024 at 07:40:34 UTC, Nick Treleaven wrote:
 On Friday, 19 April 2024 at 06:28:55 UTC, Meta wrote:
 On Wednesday, 17 April 2024 at 11:24:16 UTC, Nick Treleaven 
 wrote:
 On Tuesday, 16 April 2024 at 18:25:45 UTC, Meta wrote:
 - branch guards
 - pattern match on arrays, slices:
Some other things, based on section 3.3 of this C++ proposal: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2392r2.pdf - Multiple alternatives that have the same result: || E.g. ```d case :9 || :15 -> "not prime"; ```
This is already covered by regular switch statements. You can write: ```D case 9, 15 -> "not prime"; ```
It would be ambiguous to write e.g. `case name if (cond) ->` - is it matching a value `name`, or is `name` naming the switch variable?
I'm not quite sure what you mean - can you illustrate in more detail?
 But the grammar was me trying to extrapolate from your 
 examples, and it might not be workable for that to be 
 compatible with today's switch statement. Perhaps it's better 
 to not reuse `switch` because we will want pattern matching 
 with multiple statement branches, we won't always want `switch` 
 to be an expression.
Yeah maybe not. That was just some mock syntax off the top of my head, and it's probably not suitable for extracting a formal grammar.
 - Grouping common names and constraints: { }

 E.g.
 ```d
 switch (variant) {
     case int i {
         case if (i < 0) -> "negative int";
         default -> "some other int";
     }
 ```
```D switch (variant) { // goto default is already a feature of regular switch statements case int i -> i < 0 ? "negative int" : goto default; default -> "some other int"; } ``` This will work _if_ `goto default` is typed as `noreturn`. I doubt that's the case, but that's something that can also be fixed in the compiler.
BTW that's not what my example does - the `i < 0` is part of the matching, not part of the result. The difference is there can be other `case` statements under the first one. `case if (i < 0) ->` would try the next case statement when i >= 0 rather than jumping to the default case.
I see. I think having nested case conditions might make it too complex to understand and maybe even implement.
 Also for your example I don't understand why `goto default` 
 wouldn't have the same type as the result for the `default` 
 branch.
Conceptually, `goto default` and other constructs that transfer execution to a different part of the code should be typed as `noreturn`, because then you can do stuff like: ```D auto input = readln() || throw new Exception("empty input"); ``` Although in this case it would actually be pretty weird... I _think_ it would enable this type of code: ```D Variant v = 10; auto str = switch (variant) { case int i -> i < 0 ? "negative int" : goto default; default -> writeln("invalid value"); }; // The only sane type for `str` is `noreturn`, and thus it should crash the program if we try to read from it. ```
Apr 19
parent Nick Treleaven <nick geany.org> writes:
On Friday, 19 April 2024 at 19:27:22 UTC, Meta wrote:
 On Friday, 19 April 2024 at 07:40:34 UTC, Nick Treleaven wrote:
 On Friday, 19 April 2024 at 06:28:55 UTC, Meta wrote:
 On Wednesday, 17 April 2024 at 11:24:16 UTC, Nick Treleaven 
 wrote:
 On Tuesday, 16 April 2024 at 18:25:45 UTC, Meta wrote:
 - branch guards
 - pattern match on arrays, slices:
Some other things, based on section 3.3 of this C++ proposal: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2392r2.pdf - Multiple alternatives that have the same result: || E.g. ```d case :9 || :15 -> "not prime"; ```
This is already covered by regular switch statements. You can write: ```D case 9, 15 -> "not prime"; ```
It would be ambiguous to write e.g. `case name if (cond) ->` - is it matching a value `name`, or is `name` naming the switch variable?
I'm not quite sure what you mean - can you illustrate in more detail?
Where you had: ```d auto s = switch (input) { case n if (n == 0) -> "zero"; case n if (n > 0) -> "greater than zero"; case n if (n < 0) -> "less than zero"; ``` I understand that in the last case, it's giving input an alternative name n, then testing n < 0. But suppose n is already a symbol in scope, and the test might not involve n: case n if (p < 0) I might expect that to match when input is equal to the value of n and p is negative. But how does the parser know if n is supposed to be an alternative name for input, or to be a value looked up in the current scope. It can be figured out at semantic time, but I think it would be better to design the syntax to be unambiguous at the parser stage about whether it is introducing a new symbol or not.
 But the grammar was me trying to extrapolate from your 
 examples, and it might not be workable for that to be 
 compatible with today's switch statement. Perhaps it's better 
 to not reuse `switch` because we will want pattern matching 
 with multiple statement branches, we won't always want 
 `switch` to be an expression.
Yeah maybe not. That was just some mock syntax off the top of my head, and it's probably not suitable for extracting a formal grammar.
 - Grouping common names and constraints: { }

 E.g.
 ```d
 switch (variant) {
     case int i {
         case if (i < 0) -> "negative int";
         default -> "some other int";
     }
 ```
```D switch (variant) { // goto default is already a feature of regular switch statements case int i -> i < 0 ? "negative int" : goto default; default -> "some other int"; } ``` This will work _if_ `goto default` is typed as `noreturn`. I doubt that's the case, but that's something that can also be fixed in the compiler.
BTW that's not what my example does - the `i < 0` is part of the matching, not part of the result. The difference is there can be other `case` statements under the first one. `case if (i < 0) ->` would try the next case statement when i >= 0 rather than jumping to the default case.
I see. I think having nested case conditions might make it too complex to understand and maybe even implement.
I think it would be straightforward, but indeed could wait until later.
 Also for your example I don't understand why `goto default` 
 wouldn't have the same type as the result for the `default` 
 branch.
Conceptually, `goto default` and other constructs that transfer execution to a different part of the code should be typed as `noreturn`, because then you can do stuff like: ```D auto input = readln() || throw new Exception("empty input"); ``` Although in this case it would actually be pretty weird... I _think_ it would enable this type of code: ```D Variant v = 10; auto str = switch (variant) { case int i -> i < 0 ? "negative int" : goto default; default -> writeln("invalid value"); }; // The only sane type for `str` is `noreturn`, and thus it should crash the program if we try to read from it. ```
I would expect the default case to produce a value unless it does not terminate. So I would require writing an assert(0) at the end of it.
Apr 23
prev sibling parent ShowMeTheWay <ShowMeTheWay gmail.com> writes:
On Wednesday, 17 April 2024 at 11:24:16 UTC, Nick Treleaven wrote:
 ...
 Some other things, based on section 3.3 of this C++ proposal:
 https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2392r2.pdf

 - Multiple alternatives that have the same result: ||

 E.g.
 ```d
 case :9 || :15 -> "not prime";
 ```
 ...`
the 'switch' keyword implies old-school.. D needs a new term. and the 'case' word is superfluous. something like this perhaps: int x = 15; check x { < 0 _ => writeln!("Sorry. That's not even possible!"), 0 | 1 => writeln!("wtf!"), 2..5 => writeln!("mmm.. not too bad"), 6..10 => writeln!("that's a bit better"), 11..15 => writeln!("now you're getting it"), 20 | >20 => writeln!("Wow! I think you've got it now"), _ => writeln!("Oops! Something's not right."), }
Apr 24
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
I've thought about it for a while now. Improving switch has a lot of issues
with 
it, such as the unusual scoping rules, the ability to goto in and out of it,
the 
ability to interleave switch/case with other looping constructs (!).

It's unsalvageable.

It's better to create a new construct, let's say "match", and design an 
unconstrained syntax for it to accommodate pattern matching in particular.

("match" is already an identifier in common use, some other name would be
better.)
Apr 22
next sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 23/04/2024 4:45 AM, Walter Bright wrote:
 I've thought about it for a while now. Improving switch has a lot of 
 issues with it, such as the unusual scoping rules, the ability to goto 
 in and out of it, the ability to interleave switch/case with other 
 looping constructs (!).
 
 It's unsalvageable.
 
 It's better to create a new construct, let's say "match", and design an 
 unconstrained syntax for it to accommodate pattern matching in particular.
 
 ("match" is already an identifier in common use, some other name would 
 be better.)
I was really looking forward to your recent DConf Online talk about matching. It is why I have avoided this idea up until now, I wanted to see what you have come up with. Same thing for sum types. If you have any design work on this subject, I think other people not just myself would be interested in having a read.
Apr 22
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/22/2024 10:33 AM, Richard (Rikki) Andrew Cattermole wrote:
 I was really looking forward to your recent DConf Online talk about matching.
 
 It is why I have avoided this idea up until now, I wanted to see what you have 
 come up with.
 
 Same thing for sum types.
 
 If you have any design work on this subject, I think other people not just 
 myself would be interested in having a read.
Sumtypes must come before pattern matching. I had a proposal for it: https://www.digitalmars.com/d/archives/digitalmars/D/sumtypes_for_D_366242.html
Apr 22
prev sibling next sibling parent reply ShowMeTheWay <ShowMeTheWay gmail.com> writes:
On Monday, 22 April 2024 at 16:45:35 UTC, Walter Bright wrote:
 I've thought about it for a while now. Improving switch has a 
 lot of issues with it, such as the unusual scoping rules, the 
 ability to goto in and out of it, the ability to interleave 
 switch/case with other looping constructs (!).

 It's unsalvageable.

 It's better to create a new construct, let's say "match", and 
 design an unconstrained syntax for it to accommodate pattern 
 matching in particular.

 ("match" is already an identifier in common use, some other 
 name would be better.)
int x = 1; check x { 1 => writeln!("one"), 2 => writeln!("two"), 3 => writeln!("three"), 4 => writeln!("four"), 5 => writeln!("five"), _ => writeln!("something else"), }
Apr 23
parent ShowMeTheWay <ShowMeTheWay gmail.com> writes:
On Wednesday, 24 April 2024 at 06:52:51 UTC, ShowMeTheWay wrote:
 On Monday, 22 April 2024 at 16:45:35 UTC, Walter Bright wrote:
 I've thought about it for a while now. Improving switch has a 
 lot of issues with it, such as the unusual scoping rules, the 
 ability to goto in and out of it, the ability to interleave 
 switch/case with other looping constructs (!).

 It's unsalvageable.

 It's better to create a new construct, let's say "match", and 
 design an unconstrained syntax for it to accommodate pattern 
 matching in particular.

 ("match" is already an identifier in common use, some other 
 name would be better.)
int x = 1; check x { 1 => writeln!("one"), 2 => writeln!("two"), 3 => writeln!("three"), 4 => writeln!("four"), 5 => writeln!("five"), _ => writeln!("something else"), }
aka ..a new language construct (i.e. an improvement over a switch expression) called 'a check expression'.
Apr 23
prev sibling parent Quirin Schroll <qs.il.paperinik gmail.com> writes:
On Monday, 22 April 2024 at 16:45:35 UTC, Walter Bright wrote:
 I've thought about it for a while now. Improving switch has a 
 lot of issues with it, such as the unusual scoping rules, the 
 ability to goto in and out of it, the ability to interleave 
 switch/case with other looping constructs (!).

 It's unsalvageable.

 It's better to create a new construct, let's say "match", and 
 design an unconstrained syntax for it to accommodate pattern 
 matching in particular.

 ("match" is already an identifier in common use, some other 
 name would be better.)
There, it’s something like `string[1..$-1] switch { … }`.
Apr 25
prev sibling parent Dukc <ajieskola gmail.com> writes:
On Tuesday, 16 April 2024 at 10:34:21 UTC, ryuukk_ wrote:
 It is time to make them nice to use

 - allow them as expression
 - more concise
 - pattern match
I'm certainly open to exploring the general notion. I think Walter is too, at least regarding the last one, as I recall he has said somewhere that D will have pattern matching. However, whether we actually want to change `switch` depends on the details, exactly how are we going to do it? Every new langauge feature has to consider added language complexity, corner cases and backwards compatibility questions. How hard those are to deal with, compared to the benefit, is the ultimate test of worth for the feature. I somewhat tend to agree with Walter. `switch` works how it works thanks to C heritage, as a result it has a lot of backwards compatibility burden. Any attempt to overhaul it to support pattern matching as a primary use case is probably going to complicate the language more than just designing a new construct. But I'm not locked to this position - if someone presents a clever `switch` upgrade proposal along with the details, I'd be happy to be proven wrong.
Apr 24