February 17, 2014
On 2/17/14, 7:31 PM, Walter Bright wrote:
> On 2/17/2014 5:48 AM, Ary Borenszweig wrote:
>> On 2/16/14, 5:03 PM, Walter Bright wrote:
>>> It originally was not required, but there was a campaign by a lot of D
>>> users to make it required to deal with the common bug of adding a value
>>> in one switch statement but forgetting to add it to another
>>> corresponding one.
>>
>> Could you show an example of such scenario? I don't get it.
>
> Having a set of bit flags, and adding another bit flag later, and
> failing to account for that in existing switch statements.

auto bit_flag = ...;
switch(bit_flag) {
   case old_bit_flag_1:
     // do something
     break;
   case old_bit_flag_2:
     // do something
     break;
   default:
     break;
}

Now suppose bit_flag can get an additional "new_bit_flag" value. How does "default" helps me notice that I'm supposed to add it to that switch statement?

I still can't see your point :-(

Maybe I need some more example code to understand it.
February 17, 2014
On 2/17/2014 2:43 PM, Ary Borenszweig wrote:
> Now suppose bit_flag can get an additional "new_bit_flag" value. How does
> "default" helps me notice that I'm supposed to add it to that switch statement?

Because if you account for all the cases, you write:

   default: assert(0);

Now you intentionally tell the user that you intentionally covered all the cases.
February 17, 2014
On Monday, 17 February 2014 at 00:27:44 UTC, Namespace wrote:
> On Monday, 17 February 2014 at 00:22:52 UTC, Casper Færgemand wrote:
>> What about new evolved switch statement, called something as to not confuse it with C syntax? It could be a simple rewrite thing.
>>
>> mysteryswitch (some expression) {
>>  case 1: some statement;
>>  case 2 .. 4: some other statement;
>> }
>>
>> could rewrite to
>>
>> switch (some expression) {
>>  case 1: some statement; break;
>>  case 2: .. case 4: some other statement; break;
>>  default: break;
>> }
>
> I like 'match' as Rust has:
> ----
> match (some expression) {
>     case 1: some statement;
>     case 2 .. 4: some other statement;
> }
> ----

+1, I linked this "match". How a name does the difference. I suggest to implement this one instead of. I think that it's very nice because don't make nobody confusing anymore or break D philosofy. some-statement should have an implicit 'break' generated by the compiler just like Pascal cases have (and rust I guess)
February 18, 2014
On Mon, 17 Feb 2014 18:01:38 -0500, Walter Bright <newshound2@digitalmars.com> wrote:

> On 2/17/2014 2:43 PM, Ary Borenszweig wrote:
>> Now suppose bit_flag can get an additional "new_bit_flag" value. How does
>> "default" helps me notice that I'm supposed to add it to that switch statement?
>
> Because if you account for all the cases, you write:
>
>     default: assert(0);
>
> Now you intentionally tell the user that you intentionally covered all the cases.

Would it not be better to infer this, and you could override it by doing default: break;?

If that's the "right way", then it should be the default way.

I agree with Ary. Sequence will go as follows:

Programmer:

switch(x)
{
   case 1: statement; break;
}

Compiler: no no no, you need a default case!

Programmer: "Oh fine!"

switch(x)
{
   case 1: statement; break;
   default: break;
}

How is this advantageous? It just seems annoying...

-Steve
February 18, 2014
On 18 February 2014 08:31, Walter Bright <newshound2@digitalmars.com> wrote:

> On 2/17/2014 5:48 AM, Ary Borenszweig wrote:
>
>> On 2/16/14, 5:03 PM, Walter Bright wrote:
>>
>>> It originally was not required, but there was a campaign by a lot of D users to make it required to deal with the common bug of adding a value in one switch statement but forgetting to add it to another corresponding one.
>>>
>>
>> Could you show an example of such scenario? I don't get it.
>>
>
> Having a set of bit flags, and adding another bit flag later, and failing to account for that in existing switch statements.
>

It sounds like that's basically the same as final switch, just without the enum key to communicate the strong concept.

If I were to imagine a solution to that problem I would have also applied
final switch, but in the case it's dealing with integers and not enums and
therefore can't know which values are valid and tell you that you missed
one, it should insert an implicit 'default: assert(0);' (since final switch
isn't meant to have 'default' cases), this way any case you don't
explicitly handle is considered invalid, and you'll catch your mistake
immediately. I expect final switch on enum's must do this anyway (at least
in debug)? It's possible to receive a value that's not a recognised enum
key; what happens in that case?
It seems effectively the same to me.


February 18, 2014
On 18 February 2014 09:01, Walter Bright <newshound2@digitalmars.com> wrote:

> On 2/17/2014 2:43 PM, Ary Borenszweig wrote:
>
>> Now suppose bit_flag can get an additional "new_bit_flag" value. How does "default" helps me notice that I'm supposed to add it to that switch statement?
>>
>
> Because if you account for all the cases, you write:
>
>    default: assert(0);
>
> Now you intentionally tell the user that you intentionally covered all the cases.


I think 'final switch' should do that for you, and by typing final, you've intentionally covered the case. There's no room for mistake then.


February 18, 2014
On 18 February 2014 06:00, Walter Bright <newshound2@digitalmars.com> wrote:
>
>
> I tend to format such like this:
>
>
>          int difficulty;
>          switch(e.note.note)
>          {
>            case 60: .. case 71:  difficulty = 0;  break;
>            case 72: .. case 83:  difficulty = 1;  break;
>            case 84: .. case 95:  difficulty = 2;  break;
>            case 96: .. case 107: difficulty = 3;  break;
>            default:              difficulty = -1; break;
>          }
>
> By lining things up, it takes on a tabular appearance. People are good at inferring patterns, and such tabular arrangements make it easy to spot squeaky wheels.


Me too, but you don't feel this is basically a hack?
About half of that text is repeated cruft, and there's no precedent for
formatting well-structured code like that anywhere else in the language.
How long would you say you spend on average fiddling with the tabulation?
I am known to spend minutes pressing the space bar, trying to make it line
up and look nice. And then invariably, some other case comes along, with a
slightly longer identifier name, and you have to work your way up shifting
everything around against with a bunch more spaces.. pollutes source
control history, etc.
And then that case with the REALLY long identifier name comes along, and
you end out with so many spaces surrounding all the other cases, that it
becomes difficult to associate which line matches which case, so then you
think to yourself, "this one long case is ruining my code, maybe I should
break the pattern and fall this long one onto it's own line below...", and
then you're just wasting time, pushing the spacebar key, trying to work
around something that shouldn't have been an issue in the first place.
Often enough the break statements end up far off the right hand side of the
screen due to that one long statement in the sequence; do you line them all
up religiously far to the right? Or do you make an exception for that one
long line, allowing it to span beyond the 'break' line, and keep the rest
lined up nearer to the code they terminate?
Tell me this doesn't happen to you? Surely I'm not the only one that faces
this sort of conundrum frequently when I try and use switch? :)

I can't see that practise as anything other than a formatting hack to deal with something that was structurally unsound in the first place.


> Finally, you didn't address the suggestion to allow assignment of the switch > condition to a properly scoped variable: switch([x =] expression) ?
>
> That's probably a good idea.
>

Cool, I'll bugzilla it. At least something useful may comes from my ranting :P


February 18, 2014
On 2/17/2014 6:17 PM, Steven Schveighoffer wrote:
> How is this advantageous? It just seems annoying...

Because it makes the programmer's intent clear - are all the cases accounted for, or are there defaults?

Of course, no compiler can make you write correct code. But if you're going to write a default anyway, odds are you'll choose the right one.

February 18, 2014
On 2/17/2014 6:38 PM, Manu wrote:
> I think 'final switch' should do that for you, and by typing final, you've
> intentionally covered the case. There's no room for mistake then.

That's why a default case is not allowed for a 'final' switch.
February 18, 2014
On 2/17/2014 6:35 PM, Manu wrote:
> If I were to imagine a solution to that problem I would have also applied final
> switch, but in the case it's dealing with integers and not enums and therefore
> can't know which values are valid and tell you that you missed one, it should
> insert an implicit 'default: assert(0);' (since final switch isn't meant to have
> 'default' cases), this way any case you don't explicitly handle is considered
> invalid, and you'll catch your mistake immediately. I expect final switch on
> enum's must do this anyway (at least in debug)? It's possible to receive a value
> that's not a recognised enum key; what happens in that case?
> It seems effectively the same to me.

The 'final' works as you propose. Why not give it a whirl?