Jump to page: 1 2
Thread overview
Re: No more fall through in case statement?
Jan 03, 2008
bearophile
Jan 03, 2008
bearophile
Jan 03, 2008
Leonard Dahlmann
Jan 03, 2008
0ffh
Jan 03, 2008
Carlos Santander
Jan 04, 2008
S.
Jan 04, 2008
Bill Baxter
Jan 04, 2008
bearophile
Jan 07, 2008
S.
Jan 08, 2008
bearophile
Jan 04, 2008
Bruce Adams
Jan 07, 2008
S.
Jan 07, 2008
Bruce Adams
Jan 07, 2008
S.
Jan 08, 2008
Bill Baxter
Jan 04, 2008
James Dennett
Jan 05, 2008
Bill Baxter
Jan 12, 2008
Robert DaSilva
January 03, 2008
Bill Baxter:
> I'm no C# guy but that looks like a nice way to fix C's switch.

I think the C switch is broken in 2 or more ways, so I'd like to see D improve it. This is some code I have shown time ago:

import std.stdio: writefln;
void main(string[] args) {
  switch (args[1]) {
    int x = 1; // NOT initialized?
    case "1": writefln("1! x=", x); break;
    case "2": writefln("2! x=", x); break;
  }
}

More on switch-induced bugs: http://www.soft.com/AppNotes/attcrash.html


>"goto case 5" looks like something straight out of Walter's playbook, too.<

I don't like that goto too much... You usually just want do go down (and by default you want to go to the end of the switch).


> But it's been discussed many times now and it doesn't seem likely Walter's going to change it in D.<

I agree with Walter when he says it's better that if a syntax that looks like C works like C (D goes against this rule few times). So we need a syntax that looks different. Instead of switch{} it may be used caseof{}, plus the "default" statement, plus a new statement like "fall" (or something similar) that tells the compiler just to not break, so it's just the opposite of C :-)

As example, this is a part of the std.string.capwords function:

switch (s[i]) {
    case ' ':
    case '\t':
    case '\f':
    case '\r':
    case '\n':
    case '\v':
        if (inword) {
            r ~= capitalize(s[istart .. i]);
            inword = false;
        }
        break;

    default:
        if (!inword) {
            if (r.length)
            r ~= ' ';
            istart = i;
            inword = true;
        }
        break;
}


With that syntax it becomes:

caseof (s[i]) {
    case ' ':  fall;
    case '\t': fall;
    case '\f': fall;
    case '\r': fall;
    case '\n': fall;
    case '\v':
        if (inword) {
            r ~= capitalize(s[istart .. i]);
            inword = false;
        }

    default:
        if (!inword) {
            if (r.length)
            r ~= ' ';
            istart = i;
            inword = true;
        }
}


D already follows such "inversion rule" regerding C in some cases, like here:

int a = void;

In a safe(r) language the default syntax/behavior *must* be the safer one, expecially when this has no/little costs in terms of speed/memory.

Bye,
bearophile
January 03, 2008
bearophile:

> caseof (s[i]) {
>     case ' ':  fall;
>     case '\t': fall;
>     case '\f': fall;
>     case '\r': fall;
>     case '\n': fall;
>     case '\v':
>         if (inword) {
>             r ~= capitalize(s[istart .. i]);
>             inword = false;
>         }
> 
>     default:
>         if (!inword) {
>             if (r.length)
>             r ~= ' ';
>             istart = i;
>             inword = true;
>         }
> }

Let's try again, 2 keywords less:

caseof (s[i]) {
    case ' ':  continue;
    case '\t': continue;
    case '\f': continue;
    case '\r': continue;
    case '\n': continue;
    case '\v':
        if (inword) {
            r ~= capitalize(s[istart .. i]);
            inword = false;
        }

    else:
        if (!inword) {
            if (r.length)
            r ~= ' ';
            istart = i;
            inword = true;
        }
}

:-)

Bye,
bearophile
January 03, 2008
bearophile Wrote:

> bearophile:
> 
> > caseof (s[i]) {
> >     case ' ':  fall;
> >     case '\t': fall;
> >     case '\f': fall;
> >     case '\r': fall;
> >     case '\n': fall;
> >     case '\v':
> >         if (inword) {
> >             r ~= capitalize(s[istart .. i]);
> >             inword = false;
> >         }
> > 
> >     default:
> >         if (!inword) {
> >             if (r.length)
> >             r ~= ' ';
> >             istart = i;
> >             inword = true;
> >         }
> > }
> 
> Let's try again, 2 keywords less:
> 
> caseof (s[i]) {
>     case ' ':  continue;
>     case '\t': continue;
>     case '\f': continue;
>     case '\r': continue;
>     case '\n': continue;
>     case '\v':
>         if (inword) {
>             r ~= capitalize(s[istart .. i]);
>             inword = false;
>         }
> 
>     else:
>         if (!inword) {
>             if (r.length)
>             r ~= ' ';
>             istart = i;
>             inword = true;
>         }
> }
> 
> :-)
> 
> Bye,
> bearophile

I doubt that 'continue' can be used there - what if we have a caseof in a loop?

foreach(x; y)
{
    caseof(s[i])
    {
         case '': continue; // fallthrough or continue the loop?
    }
}

One could workaround this by giving the loop a label and using it with 'continue', but still, this might be confusing for beginners.
January 03, 2008
Leonard Dahlmann wrote:
> I doubt that 'continue' can be used there - what if we have a caseof in a loop?

Same with 'break' - what if we have a switch in a loop? =)

regards, frank
January 03, 2008
bearophile escribió:
> Bill Baxter:
>> I'm no C# guy but that looks like a nice way to fix C's switch.
>
> I think the C switch is broken in 2 or more ways, so I'd like to see D improve it. This is some code I have shown time ago:
>
> import std.stdio: writefln;
> void main(string[] args) {
>   switch (args[1]) {
>     int x = 1; // NOT initialized?
>     case "1": writefln("1! x=", x); break;
>     case "2": writefln("2! x=", x); break;
>   }
> }
>
> More on switch-induced bugs:
> http://www.soft.com/AppNotes/attcrash.html
>
>
>> "goto case 5" looks like something straight out of Walter's playbook, too.<
>
> I don't like that goto too much... You usually just want do go down (and by default you want to go to the end of the switch).
>
>
>> But it's been discussed many times now and it doesn't seem likely Walter's going to change it in D.<
>
> I agree with Walter when he says it's better that if a syntax that looks like C works like C (D goes against this rule few times). So we need a syntax that looks different. Instead of switch{} it may be used caseof{}, plus the "default" statement, plus a new statement like "fall" (or something similar) that tells the compiler just to not break, so it's just the opposite of C :-)
>
> As example, this is a part of the std.string.capwords function:
>
> switch (s[i]) {
>     case ' ':
>     case '\t':
>     case '\f':
>     case '\r':
>     case '\n':
>     case '\v':
>         if (inword) {
>             r ~= capitalize(s[istart .. i]);
>             inword = false;
>         }
>         break;
>
>     default:
>         if (!inword) {
>             if (r.length)
>             r ~= ' ';
>             istart = i;
>             inword = true;
>         }
>         break;
> }
>
>
> With that syntax it becomes:
>
> caseof (s[i]) {
>     case ' ':  fall;
>     case '\t': fall;
>     case '\f': fall;
>     case '\r': fall;
>     case '\n': fall;
>     case '\v':
>         if (inword) {
>             r ~= capitalize(s[istart .. i]);
>             inword = false;
>         }
>
>     default:
>         if (!inword) {
>             if (r.length)
>             r ~= ' ';
>             istart = i;
>             inword = true;
>         }
> }
>

How about using existing D syntax?

switch (s[i]) {
     case ' ', '\t', '\f', '\r', '\n', '\v':
         if (inword) {
             r ~= capitalize(s[istart .. i]);
             inword = false;
         }
         break;

     default:
         if (!inword) {
             if (r.length)
             r ~= ' ';
             istart = i;
             inword = true;
         }
         break;
}

>
> D already follows such "inversion rule" regerding C in some cases, like here:
>
> int a = void;
>
> In a safe(r) language the default syntax/behavior *must* be the safer one, expecially when this has no/little costs in terms of speed/memory.
>
> Bye,
> bearophile



-- 
Carlos Santander Bernal

January 04, 2008
Carlos Santander Wrote:
> 
> How about using existing D syntax?
> 
> switch (s[i]) {
>       case ' ', '\t', '\f', '\r', '\n', '\v':
>           if (inword) {
>               r ~= capitalize(s[istart .. i]);
>               inword = false;
>           }
>           break;
> 
>       default:
>           if (!inword) {
>               if (r.length)
>               r ~= ' ';
>               istart = i;
>               inword = true;
>           }
>           break;
> }

This whole conversation about switch was kind of lost on me, but I have to contribute this.

I, at various times, have written code that depends on case statements falling through, while not being identical!

For example:

switch(foo)
{
case 'bob':
    //Do bob stuff
    //Fall through and doo bar stuff too.
case 'bar':
    //Do bar stuff and exit
    break;

case 'baz':
   //Do some baz stuff
   break;
}

Whatever is changed shouldn't break this.
January 04, 2008
S. wrote:

> This whole conversation about switch was kind of lost on me, 

Don't worry, none of it will ever happen in D, anyway.

> but I have to contribute this.
> I, at various times, have written code that depends on case statements falling through, while not being identical!
> 
> For example:
> 
> switch(foo)
> {
> case 'bob':
>     //Do bob stuff
>     //Fall through and doo bar stuff too.
> case 'bar':
>     //Do bar stuff and exit       break;
> 
> case 'baz':
>    //Do some baz stuff
>    break;
> }
> 
> Whatever is changed shouldn't break this.

Good news for you, then.  Nothing's going to change!

But man I wish it would, for 2.0 that is.  I've been hit at least half-a-dozen times in the past year by missing break statements in my D code.  And I have a C++ background!  So it's not about familiarity.  It bites me when I'm coding C++ just as frequently.  It's simply a C/C++ mis-feature that D failed to correct.

--bb
January 04, 2008
S. Wrote:
> I, at various times, have written code that depends on case statements falling through, while not being identical!

If you take a look at my original post, I have suggested to use a "fall" or "continue" statement when you want to go down, and nothing if you want the default of going at the end of the switch...

Bye,
bearophile
January 04, 2008
On Fri, 04 Jan 2008 00:15:25 -0000, S. <S@s.com> wrote:

> Carlos Santander Wrote:
>>
>> How about using existing D syntax?
>>
>> switch (s[i]) {
>>       case ' ', '\t', '\f', '\r', '\n', '\v':
>>           if (inword) {
>>               r ~= capitalize(s[istart .. i]);
>>               inword = false;
>>           }
>>           break;
>>
>>       default:
>>           if (!inword) {
>>               if (r.length)
>>               r ~= ' ';
>>               istart = i;
>>               inword = true;
>>           }
>>           break;
>> }
>
> This whole conversation about switch was kind of lost on me, but I have to contribute this.
>
> I, at various times, have written code that depends on case statements falling through, while not being identical!
>
> For example:
>
> switch(foo)
> {
> case 'bob':
>     //Do bob stuff
>     //Fall through and doo bar stuff too.
> case 'bar':
>     //Do bar stuff and exit
>     break;
>
> case 'baz':
>    //Do some baz stuff
>    break;
> }
>
> Whatever is changed shouldn't break this.

This whole conversation boggles me. cases should *never* fall through its dangerous.
Assuming polymorphism isn't the answer, which can often eliminate the switch altogether
its much cleaner, safer and better encapsulated in general to use a function call
to replace fall through. E.g. :

handleBar()
{
  //Do bar stuff
}

switch(foo)
{
case 'bob':
    // do bob stuff
    handleBar();
case 'bar':
    handleBar();
case 'baz':
    // do baz stuff
}

The switch can always compile to a simple look-up table that way.

January 04, 2008
bearophile wrote:
> Bill Baxter:
>> I'm no C# guy but that looks like a nice way to fix C's switch.
> 
> I think the C switch is broken in 2 or more ways, so I'd like to see D improve it. This is some code I have shown time ago:
> 
> import std.stdio: writefln;
> void main(string[] args) {
>   switch (args[1]) {
>     int x = 1; // NOT initialized?
>     case "1": writefln("1! x=", x); break;
>     case "2": writefln("2! x=", x); break;
>   }
> }

C++ fixed this some time in the last century, making the code
above ill-formed (diagnostic required) as it skips the initialization
of x.

(It's still UB in C99 so far as I know.)

-- James
« First   ‹ Prev
1 2