Jump to page: 1 2
Thread overview
Switch statement (again)
Aug 27, 2002
C.R.Chafer
Aug 27, 2002
Suporte Internet
Aug 27, 2002
C.R.Chafer
Aug 27, 2002
Richard Krehbiel
Aug 27, 2002
C.R.Chafer
Aug 27, 2002
Mac Reiter
Aug 27, 2002
C.R.Chafer
Aug 27, 2002
Pavel Minayev
Aug 28, 2002
Sean L. Palmer
Aug 28, 2002
Joel Lucsy
Aug 29, 2002
anderson
Aug 29, 2002
anderson
Aug 29, 2002
C.R.Chafer
Aug 29, 2002
Mark Evans
Aug 30, 2002
Pavel Minayev
Aug 30, 2002
anderson
Re: Switch statement
Aug 30, 2002
C.R.Chafer
Aug 30, 2002
Sean L. Palmer
Aug 31, 2002
anderson
Aug 31, 2002
C.R.Chafer
August 27, 2002
Just because I like metaphorically beating dead horses...

How about the following alterating to the switch statement

int a = /* blah */;
switch( a )
{
        case 0:
                /* do something */
                /* fall through */
        case 1:
                /* do something else */
                /* implicit break; */
        case 10
        {
                /* do something */
                /* implicit break; */
        }
        case 11 {}      /* do nothing (implicit break) */
        default:
                /* do something */
}

The idea is that the cases have two formats, one that follows the normal C
syntax and a new format utilising an implicit break.
The traditional format looks (and works) like a label where the new format
looks (and works) like a block.
This will allow normal C programmes to work in their original format
(though this format may be deprecated) and newer D programmes to use the
implicit break semantics.
Parsing the new format should be simple.
The only problem I can see is that ...
        case 1: { }
and     case 1{}
are different - maybe the former case (case1:{}) should not be supported?

C 2002/8/27
August 27, 2002
C.R.Chafer <blackmarlin@nospam.asean-mail.com> wrote:
> How about the following alterating to the switch statement
> 
> int a = /* blah */;
> switch( a )
> {
>        case 0:
>                /* do something */
>                /* fall through */
>        case 1:
>                /* do something else */
>                /* implicit break; */
>        case 10
>        {
>                /* do something */
>                /* implicit break; */
>        }
>        case 11 {}      /* do nothing (implicit break) */
>        default:
>                /* do something */
> }

Good idea !
And use the break for loop statements as Pavel have sugested:

for (;;){
	i = getValue();
	case (i) {
		1 : codeBeforeNextIteration();
		2 {
			nextIteration();
		}
		3 : 4 : 5 {
			anotherIteration();
		}
		6 : break; // out of for loop
	}
}

> The only problem I can see is that ...
>        case 1: { }
> and     case 1{}
> are different - maybe the former case (case1:{}) should not be supported?
August 27, 2002
"C.R.Chafer" <blackmarlin@nospam.asean-mail.com> wrote in message news:akfqu3$23s7$1@digitaldaemon.com...
> Just because I like metaphorically beating dead horses...
>
> How about the following alterating to the switch statement
>
> int a = /* blah */;
> switch( a )
> {
>         case 0:
>                 /* do something */
>                 /* fall through */
>         case 1:
>                 /* do something else */
>                 /* implicit break; */
>         case 10
>         {
>                 /* do something */
>                 /* implicit break; */
>         }
>         case 11 {}      /* do nothing (implicit break) */
>         default:
>                 /* do something */
> }
>
> The idea is that the cases have two formats, one that follows the normal C
> syntax and a new format utilising an implicit break.
> The traditional format looks (and works) like a label where the new format
> looks (and works) like a block.

Look at subtle difference between

case 1 { }
  and
case 1: { }

The second case too similar to the first, fully acceptable to the compiler, and implies a fallthrough behavior.  This is a typo begging to happen.

My personal belief is:

1. Case enumerations ("case 1, 2, 3:") and ranges ("case 1..5:") should be
supported; and
2. Fallthrough behavior should be eliminated; all cases have an implicit
break.

In the last tiny few percent of cases where a deliberate fallthrough is needed, you can use a plain old goto.

(...and I'm soooooo not concerned with training the legions of C, C++, and Java programmers.  Basic programmers have been doing it this way for a long time, and if they can do it, so can we.)

--
Richard Krehbiel, Arlington, VA, USA
rich@kastle.com (work) or krehbiel3@comcast.net  (personal)


August 27, 2002
Richard Krehbiel wrote:

> Look at subtle difference between
> 
> case 1 { }
>   and
> case 1: { }
> 
> The second case too similar to the first, fully acceptable to the
> compiler,
> and implies a fallthrough behavior.  This is a typo begging to happen.

That is why I recommend the compiler checks for this and disallows it (in my opinion { ... } statements are useless and should be disallowed anyway - however they are there for C compatibility.

Thinking further maybe requireing brackets around the no fall though case
would solve this problem (and fit in even better with the D syntax ).. for
example..
        switch( a ) {
                case 1 :                /* std C */
                case( 2 ) {
                                /* no fall though D case */
                }
                default {
                                /* statements */
                }
        }

Of course mixing fall though and none fall though cases would not be recommended.  The compiler may even specifically disallow it (forcing the programmer to use gotos to implement fall through) or report that C style fall through case statements are deprecated (but still supported).  If these options were selected then I suspect such expected typos would become very rare.

And surely though having fallthough is just asking for similar mistakes to
such a typo (id est forgetting the break;) which would be far more
difficult for the compiler to spot.

> My personal belief is:
> 
> 1. Case enumerations ("case 1, 2, 3:") and ranges ("case 1..5:") should be
> supported; and

I think this is already supported - which is why I failed to mention it.

> 2. Fallthrough behavior should be eliminated; all cases have an implicit break.

Yes, but the reason fall thoughs are maintained is for C compatibility -
and this is the main argument for keeping C compatible syntax (also see
operator precidence, etcetra). There is no reason not to deprecate them
though.

> In the last tiny few percent of cases where a deliberate fallthrough is needed, you can use a plain old goto.
> 
> (...and I'm soooooo not concerned with training the legions of C, C++, and Java programmers.  Basic programmers have been doing it this way for a long time, and if they can do it, so can we.)

I see no recommendations for making D like BASIC :-)

C 2002/8/27

Off topic:

My ideal switch statement is the one used by OOMIC (well I did design it) but OOMIC and D syntax is very different in some areas and as a result I would not recommend an exact match.
August 27, 2002
Suporte Internet wrote:

> Good idea !

Thanks :-)

> And use the break for loop statements as Pavel have sugested:
> 
> for (;;){
> i = getValue();
> case (i) {
> 1 : codeBeforeNextIteration();
> 2 {
> nextIteration();
> }
> 3 : 4 : 5 {
> anotherIteration();
> }
> 6 : break; // out of for loop
> }
> }

I think using labeled breaks for such a piece of code would be preferable.

lbl: for(;;) switch( a ) {
        case( 100 ) { break lbl; }
        default { ++a }
}

And I still like the (much) earlier idea (though I can not remember who proposed it) of having continue work on switch statements as well as break - which would be very useful for implementing state machines.

C 2002/8/27
August 27, 2002
>That is why I recommend the compiler checks for this and disallows it (in my opinion { ... } statements are useless and should be disallowed anyway - however they are there for C compatibility.

Slightly off topic, but in C/C++, the

case:
{
int i;
for (i=0; i<a.length; ++i) {/*something*/}
}
break;

form is handy, because it gives you a scope where you can create "little" variables that are only used and only useful for that particular case.  Without the extra scope, you have to put all these variables somewhere above the switch. While style guidelines vary, and some are deadset against the "declare it just before you use it" approach, others require it.  While I don't particularly care if we keep C syntax (having worked with switch-like statements in several languages), I would hate to see an otherwise valid syntax ruled illegal, thus disabling one of the more prevalent style guidelines.

I also hate the idea of "case{}" being different from "case:{}", even *if* one of them is illegal.

Being a bit of an explicitness nut, it wouldn't particularly bother me to say that every case *must* end with either 'break' or 'fallthrough' (or 'continue', but then we confuse the loop issue even more).  Since I also hate not being able to break out of a loop from inside a switch, it might be better to make a new keyword altogether, like 'endcase'.  Of course, if you have endcase, maybe fallthrough should be nextcase...  Anyway, whatever the syntax, the idea is to simply not have a default behavior at the end of the case.  No matter what you want to do, you have to explicitly state it, so you can't possibly make an error by omission.

switch(state)
{
case START:
// something
state = FIRST;
nextcase;
case FIRST:
// first state handling
endcase;
case SECOND:
// second state handling
default: // ERROR: failed to state how to terminate "case SECOND:"
}

If you use 'break' instead of 'endcase', the copy/paste C code issue goes away. For the 99% of code that breaks after every case, nothing changes.  For the remaining code, a clear error message is printed, requiring that the programmer specify what to do at the end of the case.

Personally, I'd rather stop using C syntax (break keyword, that is), so that break and continue can continue to break out of loops.  Search-and-replace on a selected piece of code is supported in nearly all editors, so it wouldn't be that hard to switch 'break' to 'endcase' on any imported C code.

I also like the BASIC ranges and selection system, as someone (sorry...) mentioned in a previous post.  It is not enough, by itself, but combined with the fallthrough system it can be very concise and elegant.  Having done a lot of Visual Basic programming at one point in my career, I learned to appreciate the ranges and hate the lack of fallthrough.  Without fallthrough, you end up using a superset of the range in the case, and then either doing another switch or an 'if' statement to filter out particular cases that would have been in the portion of code in front of the fallthrough.

Having warped my head around C fallthrough, it doesn't matter tremendously to me either way, although I would be happier if this source of ongoing typo bugs would go away...

Mac


August 27, 2002
Mac Reiter wrote:

>>That is why I recommend the compiler checks for this and disallows it (in my opinion { ... } statements are useless and should be disallowed anyway - however they are there for C compatibility.
> 
> Slightly off topic, but in C/C++, the
> 
> case:
> {
> int i;
> for (i=0; i<a.length; ++i) {/*something*/}
> }
> break;

Yes, though I know about this form I never use it - that is why I think it
useless, together with the fact that an intellegent compiler should be able
to optimise away the need for this.

> form is handy, because it gives you a scope where you can create "little"
> variables that are only used and only useful for that particular case.
> Without the extra scope, you have to put all these variables somewhere
> above the switch. While style guidelines vary, and some are deadset
> against the "declare it just
> before you use it" approach, others require it.  While I don't
> particularly care if we keep C syntax (having worked with switch-like
> statements in several languages), I would hate to see an otherwise valid
> syntax ruled illegal, thus disabling one of the more prevalent style
> guidelines.

I personally like the Ada syntax if we are going for established languages.

> I also hate the idea of "case{}" being different from "case:{}", even *if* one of them is illegal.

Yes, after some though I tend to agree.
The suggestion case( val ){ .. }
        case_statement
        :       "case" "(" case_literal ")" "{" statements "}"
        |       "case" case_literal ":" statements
        ;

> Being a bit of an explicitness nut, it wouldn't particularly bother me to say that every case *must* end with either 'break' or 'fallthrough' (or 'continue',

Seems a good idea.

> but then we confuse the loop issue even more).  Since I also hate not
> being able to break out of a loop from inside a switch, it might be better
> to make a new
> keyword altogether, like 'endcase'.  Of course, if you have endcase, maybe
> fallthrough should be nextcase...

If we go down this path how about "continue case;" or "continue switch;"
This has the following advantages
        (1) LR(1) [I think LL(1) to] parseable syntax
        (2) no new keywords
        (3) fairly obvious meaning
        (4) compatible with C (with minor porting effort)
And then use your rule "if there is no break and no fallthough specifier
then report error".
Though this would cause a few problems when porting C code they should be
easy to track down and fix (and may even highlight some bugs in the code).

> Anyway, whatever the syntax, the idea is to
> simply not have a default behavior at the end of the case.  No matter what
> you want to do, you have to explicitly state it, so you can't possibly
> make an error by omission.
> 
> switch(state)
> {
> case START:
> // something
> state = FIRST;
> nextcase;
> case FIRST:
> // first state handling
> endcase;
> case SECOND:
> // second state handling
> default: // ERROR: failed to state how to terminate "case SECOND:"
> }
> 
> If you use 'break' instead of 'endcase', the copy/paste C code issue goes away.

As we can use "break toLabel;" I see no reason to not use break.

> For the 99% of code that breaks after every case, nothing changes.  For the remaining code, a clear error message is printed, requiring that the programmer specify what to do at the end of the case.

[OT: More like 70-80% looking at my code - but that is not a problem -
however when combined with ranges and selections (ie. "case 1,2,5..7:") I
almost never need fall throughs]

> Personally, I'd rather stop using C syntax (break keyword, that is), so
> that
> break and continue can continue to break out of loops.  Search-and-replace
> on a selected piece of code is supported in nearly all editors, so it
> wouldn't be that hard to switch 'break' to 'endcase' on any imported C
> code.

I would rather extend continue to work with switches - I think we should call it quits and just keep doing whatever D is doing now (or have a vote on it).

> I also like the BASIC ranges and selection system, as someone (sorry...)
> mentioned in a previous post.  It is not enough, by itself, but combined
> with
> the fallthrough system it can be very concise and elegant.  Having done a
> lot of Visual Basic programming at one point in my career, I learned to
> appreciate the
> ranges and hate the lack of fallthrough.  Without fallthrough, you end up
> using a superset of the range in the case, and then either doing another
> switch or an 'if' statement to filter out particular cases that would have
> been in the portion of code in front of the fallthrough.

Agreed, though goto can emulate fall through (at the expense of purety).

> Having warped my head around C fallthrough, it doesn't matter tremendously to me either way, although I would be happier if this source of ongoing typo bugs would go away...
> 
> Mac

Me neither - I just remember having to explain this to a group of first year students,  and as a result simple rules and a consistant language really helps matters .. an aspect where C falls short.

C 2002/8/27
August 27, 2002
On Tue, 27 Aug 2002 19:59:23 +0000 (UTC) Mac Reiter <Mac_member@pathlink.com> wrote:

> Being a bit of an explicitness nut, it wouldn't particularly bother me to say that every case *must* end with either 'break' or 'fallthrough' (or
'continue',
> but then we confuse the loop issue even more).  Since I also hate not being
able

No! It's already there in C#, and it is just _awful_. As one smart person
said, "if it wants a break there,
why the $@&% it doesn't put it by itself?!". I wholeheartedly agree. Just make
non-fallthru behavior
default.
August 28, 2002
"Richard Krehbiel" <rich@kastle.com> wrote in news:akg8a1$2j04$1@digitaldaemon.com:

> My personal belief is:
> 
> 1. Case enumerations ("case 1, 2, 3:") and ranges ("case 1..5:")
> should be supported; and
> 2. Fallthrough behavior should be eliminated; all cases have an
> implicit break.
> 
> In the last tiny few percent of cases where a deliberate fallthrough is needed, you can use a plain old goto.

How about this in addition to:
switch (something)
{
    	case 0:
    	    	/*dosomething and fallthru to case 1*/
    	nobreak case 1:
    	    	/*dosomething else*/
    	case 2:
    	    	/*dosomething entirely else, case 1 won't get here*/
}

August 28, 2002
"C.R.Chafer" <blackmarlin@nospam.asean-mail.com> wrote in message news:akggiv$2so7$1@digitaldaemon.com...
> That is why I recommend the compiler checks for this and disallows it (in my opinion { ... } statements are useless and should be disallowed
anyway -
> however they are there for C compatibility.

The brackets (in C++) are there to allow one to declare local variables inside the case.  Yes, this does get used in practice.

Sean




« First   ‹ Prev
1 2