April 01, 2023
The design is so the user has to intentionally choose what to do with values not in the cases:

1. all cases are accounted for, so "final"

2. other cases are to get default handled, so "default:"

The person reviewing the code is never left in doubt as to the intention of the author of the switch.

Yes, it has prevented bugs in my code.
April 01, 2023

On Friday, 31 March 2023 at 23:52:29 UTC, Steven Schveighoffer wrote:

>

On 3/31/23 6:14 PM, Sebastiaan Koppe wrote:

>

On Friday, 31 March 2023 at 21:24:25 UTC, Steven Schveighoffer wrote:

>

If you "forget a case statement", or refactor it, forcing you to write default: break; doesn't fix that.

Whenever I do write then, I do it reluctantly and mostly as a last resort.

So I do it when it makes sense that I only want to do something for the cases I specify.

But that's not my point. If your code is:

switch(x)
{
  case 0:
    doCase0;
    break;
  case 1:
    doCase1;
    break;
}

And you forgot case 42, it doesn't say "you forgot case 42". It says "you forgot the default case". So then you add default: break; and case 42 is still not there -- because you forgot it.

If you refactor, and default: break; is already there, it doesn't complain.

How often does anyone use "default: break"?

i pretty much exclusively use "default: assert(0)"

If i have cases that do nothing I still put them in, default is there to catch stuff ive forgoten.

April 01, 2023

On Saturday, 1 April 2023 at 07:32:28 UTC, claptrap wrote:

>

How often does anyone use "default: break"?

If you are a lazy (actually talented) programmer 😀

In fact, if you use enums, the compiler will warn you with the comment in the code.
But this way program produces 2 lines of output likes this:

>

humid: 2
I'm in Silifke Asthma Cave

I learned this method from Walter in Dconf'22. Remove the toggle-comment at the beginning of the final to try.

enum Weather { hot, humid, cold,
             sunny, windy, cloudy,
         drizzling, rainy, foggy
}

string shallWeGo(Weather w)
{
    //final switch(w) {/*
    switch(w) {
       default: return home();//*/
       case Weather.hot:
         w.writeln(": ", 1);
         return sea();
       case Weather.humid:
         w.writeln(": ", 2);
         return cave();
       case Weather.sunny:
         w.writeln(": ", 3);
         return beach();
       case Weather.cloudy:
         w.writeln(": ", 3);
         return home;
    }
}

import std.stdio;
void main()
{
    auto choice = Weather.humid;
    choice.shallWeGo().writeln;
}

auto sea() => "";
auto home() => "";
auto cave()
    => "I'm in Silifke Asthma Cave";
auto beach() => "";

/* Without the final keyword you will get a compilation error:
onlineapp.d(8): Error: missing cases for `enum` members in `final switch`:
onlineapp.d(8):        `cold`
onlineapp.d(8):        `windy`
onlineapp.d(8):        `drizzling`
onlineapp.d(8):        `rainy`
onlineapp.d(8):        `foggy`
*/

SDB@79

April 01, 2023

On Friday, 31 March 2023 at 15:20:41 UTC, Steven Schveighoffer wrote:

>

If we wanted to relax this requirement it's actually an easy change -- no currently-compiling code will break.

Why not? How much does this rule help you, vs. annoy you?

-Steve

On the one hand, it's not nearly always that I wish to break in the default case, often I want to assert(0) instead. This idea would encourage not checking for erroneous states, which is worse than usual since this check is free or almost free in runtime.

On the other hand, I sure like short code and it'd also be in line with what C and C++ do.

On balance, I maybe prefer current behaviour. D in general places greater emphasis on hardening the code against bugs than most languages do. It's not Ada or Rust, but still. If we were talking about a typical quick-and-dirty scripting language, the change could fit it better, but it's not as good for D IMO.

April 02, 2023
On Friday, 31 March 2023 at 21:24:25 UTC, Steven Schveighoffer wrote:
> If you "forget a case statement", or refactor it, forcing you to write `default: break;` doesn't fix that.
`dafault: assert(0);` does.

April 02, 2023
On Sunday, 2 April 2023 at 10:33:28 UTC, Jack Applegame wrote:
> On Friday, 31 March 2023 at 21:24:25 UTC, Steven Schveighoffer wrote:
>> If you "forget a case statement", or refactor it, forcing you to write `default: break;` doesn't fix that.
> `default: assert(0);` does.

Yup. I like that - much better default.
Except for assert(0) not providing any message. So if you run into this, it's still not obvious where to find the bug.
April 02, 2023
On 4/2/23 07:07, Dom Disc wrote:
> On Sunday, 2 April 2023 at 10:33:28 UTC, Jack Applegame wrote:
>> On Friday, 31 March 2023 at 21:24:25 UTC, Steven Schveighoffer wrote:
>>> If you "forget a case statement", or refactor it, forcing you to
>>> write `default: break;` doesn't fix that.
>> `default: assert(0);` does.
>
> Yup. I like that - much better default.
> Except for assert(0) not providing any message. So if you run into this,
> it's still not obvious where to find the bug.

'final switch', which Steve included in his OP, does that. The error message points at the 'switch' line:

void main(string[] args) {
    final switch (args.length) {    // Line 1106
        case 1:
            break;
    }
}

produces

$ ./deneme my-arg
core.exception.SwitchError@deneme.d(1106): No appropriate switch clause found
[...]

Although it's good enough, it could include the value that did not match a clause like "... for '2'." However, it's always tricky to print just any value for various reasons:

- A string expression may be too long to be useful; so, some trimming may have to be performed, which may trim the distinguishing parts of a string.

- Sensitive data may be dumped to the user.

Ali

April 02, 2023

On 3/31/23 11:20 AM, Steven Schveighoffer wrote:

>

Why not? How much does this rule help you, vs. annoy you?

Thanks for all the replies and discussion.

I have realized from all of this that there is a major difference between if and switch which justifies the requirement: switch can only do single-value comparison. I.e. it has to be the equivalent of if(a == b), whereas if can cover any number of cases or patterns based on boolean logic and comparisons. This makes it a lot easier to cover all the cases you need in one go.

switch on the other hand, can only cover the cases you specify. In something like an int or even a byte, that means full coverage is unwieldy or near impossible. Even with case range statements, those actually just get expanded to all the intermediate cases. So forgetting go cover cases is much more likely.

So I withdraw the suggestion. It also gives me a much better response to "why does D do this?"

-Steve

April 02, 2023

On Friday, 31 March 2023 at 15:20:41 UTC, Steven Schveighoffer wrote:

>

But we have such a thing, in the default: case requirement.
...
If we wanted to relax this requirement it's actually an easy change -- no currently-compiling code will break.

Why not? How much does this rule help you, vs. annoy you?

I rarely use switch at all. Most of the time, it's too verbose to my taste, and has little benefit compared to a chain of if-else-if. On top of that, I pause to ponder what is the Right(TM) indentation style.

When I do use switch -- or a chain of if-else-if for that matter -- it often ends with a default case with assert(false) or similar. Or it should -- so, I do have a use for the default being required.

That said, given the verboseness of switch, I see a valid reason to question the current state.

Ivan Kazmenko.

April 02, 2023

On Friday, 31 March 2023 at 15:20:41 UTC, Steven Schveighoffer wrote:

>

Imagine if every if statement required you to write an else clause,

(This doesn't seem like that much of a radical idea, considering that this is the case in functional languages, right?)

>

it's usually because I forgot to include default: break;.

One small observation, you don't need to add break; before }. (The compiler doesn't emit warnings on missing break, but on fall-through, and reaching } isn't a fall-through.) Sometimes I add a comment explaining why the default case does nothing, instead of raising an exception or something like that.