A "goto" construct in C#? What were they thinking?!

  • Thread starter Thread starter Mike Hofer
  • Start date Start date
M

Mike Hofer

While I'd toyed with C, C++, and Java over the last 20 years or so, my
principal language has been BASIC, QBASIC, then Visual Basic, and
finally Visual Basic .NET. But lately, I've been using C# and I
absolutely *love* it. It makes me think more about what I'm doing it
before I just spew code into the editor. I'm writing better code than
ever.

The only thing so far that I don't like about it is the switch
construct. I can't do this:

switch(student.Grade) {
case "1", "2", "3", "4", "5", "6":
school = "Elementary";
break;
case "7", "8", "9":
school = "Junior High";
break;
default:
school = "High School";
break;
}

Instead, I have to do this:

switch(student.Grade) {
case "1":
school = "Elementary";
break;
case "2":
goto case "1";
break;
 
Mike said:
While I'd toyed with C, C++, and Java over the last 20 years or so, my
principal language has been BASIC, QBASIC, then Visual Basic, and
finally Visual Basic .NET. But lately, I've been using C# and I
absolutely *love* it. It makes me think more about what I'm doing it
before I just spew code into the editor. I'm writing better code than
ever.

The only thing so far that I don't like about it is the switch
construct. I can't do this:

switch(student.Grade) {
case "1", "2", "3", "4", "5", "6":
school = "Elementary";
break;
case "7", "8", "9":
school = "Junior High";
break;
default:
school = "High School";
break;
}

Instead, I have to do this:

switch(student.Grade) {
case "1":
school = "Elementary";
break;
case "2":
goto case "1";
break;
.
.
.
}

In other words, you don't appear to be able to combine cases without
using a goto construct.

<RANT>A frickin' GOTO!!!! What in the heck were they thinking?! I
thought we were supposed to be moving AWAY from spaghetti
code!!!</RANT>

So my question to you all is, how do you deal with scenarios where you
need a single block to handle multiple cases, as shown above? From a
coding perspective, is there a more elegant way to do it?

Also, I notice that they added full support for goto--according to the
C# language reference, you can label lines and then use goto to
transfer execution to that line. To me, this smacks of old unstructured
BASIC code. Does anyone use this functionality in production code?
Under what circumstances do you find it useful, if at all? I guess I'm
just trying to figure out how Microsoft justified including a keyword
that seems to be pretty universally loathed in a brand new language
that's designed to be object oriented (and thereby inherently
structured).

Thanks much for your input!
 
you can use else if blocks and if(student.Grade == 1 || student.Grade == 2
......
or student.Grade < 7
 
We had this conversation a while back. In six years of using C# I've used
goto about twice.

You can use the switch statement like this:

switch(grade)
{
case 1:
case 2:
case 3:
school=Elementary;
break;
case 4:
case 5:
......
}

and so-on...

--
Bob Powell [MVP]
Visual C#, System.Drawing

Ramuseco Limited .NET consulting
http://www.ramuseco.com

Find great Windows Forms articles in Windows Forms Tips and Tricks
http://www.bobpowell.net/tipstricks.htm

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/faqmain.htm

All new articles provide code in C# and VB.NET.
Subscribe to the RSS feeds provided and never miss a new article.
 
Mike Hofer said:
While I'd toyed with C, C++, and Java over the last 20 years or so, my
principal language has been BASIC, QBASIC, then Visual Basic, and
finally Visual Basic .NET. But lately, I've been using C# and I
absolutely *love* it. It makes me think more about what I'm doing it
before I just spew code into the editor. I'm writing better code than
ever.

The only thing so far that I don't like about it is the switch
construct. I can't do this:

switch(student.Grade) {
case "1", "2", "3", "4", "5", "6":
school = "Elementary";
break;
case "7", "8", "9":
school = "Junior High";
break;
default:
school = "High School";
break;
}

Instead, I have to do this:

switch(student.Grade) {
case "1":
school = "Elementary";
break;
case "2":
goto case "1";
break;
.
.
.
}

In other words, you don't appear to be able to combine cases without
using a goto construct.

<RANT>A frickin' GOTO!!!! What in the heck were they thinking?! I
thought we were supposed to be moving AWAY from spaghetti
code!!!</RANT>

So my question to you all is, how do you deal with scenarios where you
need a single block to handle multiple cases, as shown above? From a
coding perspective, is there a more elegant way to do it?

Also, I notice that they added full support for goto--according to the
C# language reference, you can label lines and then use goto to
transfer execution to that line. To me, this smacks of old unstructured
BASIC code. Does anyone use this functionality in production code?
Under what circumstances do you find it useful, if at all? I guess I'm
just trying to figure out how Microsoft justified including a keyword
that seems to be pretty universally loathed in a brand new language
that's designed to be object oriented (and thereby inherently
structured).

Thanks much for your input!

switch(student.Grade)
{
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
school = "Elementary";
break;
case "7":
case "8":
case "9":
school = "Junior High";
break;
default:
school = "High School";
break;
}

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk
 
Mike,

A case can "fall through" as long as it doesn't contain any statements.

switch (student.Grade)
{
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
school = "Elementary";
break;
case "7":
case "8":
case "9":
school = "Junior High";
break;
default:
school = "High School";
break;
}

Brian
 
The only thing so far that I don't like about it is the switch
construct. I can't do this:

switch(student.Grade) {
case "1", "2", "3", "4", "5", "6":
school = "Elementary";
break;
case "7", "8", "9":
school = "Junior High";
break;
default:
school = "High School";
break;
}

Instead, I have to do this:

switch(student.Grade) {
case "1":
school = "Elementary";
break;
case "2":
goto case "1";
break;
}

Where, exactly, did you get THAT idea?????

In other words, you don't appear to be able to combine cases without
using a goto construct.

Sure you can

<RANT>A frickin' GOTO!!!! What in the heck were they thinking?! I
thought we were supposed to be moving AWAY from spaghetti
code!!!</RANT>

<CounterRant>
Couldn't you ask the question in a civilized fashion before ASSuming that this was the case?
So my question to you all is, how do you deal with scenarios where you
need a single block to handle multiple cases, as shown above? From a
coding perspective, is there a more elegant way to do it?

switch(student.Grade)
{
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
school = "Elementary";
break;
case "7":
case "8":
case "9":
school = "Junior High";
break;
default:
school = "High School";
break;
}

A little more verbose, but, the same concept.

Also, I notice that they added full support for goto--according to the
C# language reference, you can label lines and then use goto to
transfer execution to that line. To me, this smacks of old unstructured
BASIC code. Does anyone use this functionality in production code?

There was a recent thread on this topic. Feel free to look it up
Under what circumstances do you find it useful, if at all? I guess I'm
just trying to figure out how Microsoft justified including a keyword
that seems to be pretty universally loathed in a brand new language
that's designed to be object oriented (and thereby inherently
structured).

They chose to allow advanced developers the chance to optimize their code when the situation
warranted it, rather than forcing us all to walk "The One True Path".

Bill
 
You can do this:

switch(student.Grade) {
case "1":
case "2":
case "3":
case "4":
school = "Elementary";
break;
case "7":
case "8":
case "9":
school = "Junior High";
break;
default:
school = "High School";
break;
}

Hope this is usefull.

Kind Regards
 
Brian said:
Mike,

A case can "fall through" as long as it doesn't contain any statements.

switch (student.Grade)
{
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
school = "Elementary";
break;
case "7":
case "8":
case "9":
school = "Junior High";
break;
default:
school = "High School";
break;
}

Brian

AH!!! When I tried this earlier, I had some blocks that had code, and
wouldn't fall through. Now I know why.

WHAT A RELIEF!!!

THANKYOUTHANKYOUTHANKYOUTHANKYOUTHANKYOU!
 
Hi Mike,

There's plenty of discussions about goto in C# over the years, so you can
find more information about it. Goto is useful in the proper context - I've
only used them a couple times in the past ~5 years. It can allow you to do
a few things that are very messy to do with just if statements and breaks.
The MSDN documentation has some examples - try rewriting them without goto
(which is possible, of course), and look at the difference in the
cleanliness of the code. So, if the point of avoiding goto is to avoid
spaghetti code, then the point of using goto should also be to avoid
spaghetti code. Thankfully, the gotos in C# are scoped and labeled, so you
won't see much spaghetti with C# gotos.

Cheers,

Richard Hein
 
Bill said:
Where, exactly, did you get THAT idea?????
From the online documentation, actually. Here's what it says:

----------------------------------------------------------------------
The switch statement is a control statement that handles multiple
selections by passing control to one of the case statements within its
body. It takes the following form:

switch (expression)
{
case constant-expression:
statement
jump-statement
[default:
statement
jump-statement]
}
Where:

expression
An integral or string type expression.
statement
The embedded statement(s) to be executed if control is transferred
to the case or the default.
jump-statement
A jump statement that transfers control out of the case body.
constant-expression
Control is transferred to a specific case according to the value of
this expression.

Remarks

Control is transferred to the case statement whose constant-expression
matches expression. The switch statement can include any number of case
instances, but no two case constants within the same switch statement
can have the same value. Execution of the statement body begins at the
selected statement and proceeds until the jump-statement transfers
control out of the case body.

NOTICE THAT THE JUMP-STATEMENT IS REQUIRED AFTER EACH BLOCK, including
the last block whether it is a case statement or a default statement.
Unlike the C++ switch statement, C# does not support an explicit fall
through from one case label to another. If you want, you can use goto a
switch-case, or goto default.

If expression does not match any constant-expression, control is
transferred to the statement(s) that follow the optional default label.
If there is no default label, control is transferred outside the
switch.
----------------------------------------------------------------------

(Emphasis mine.) From that statement, I concluded that you had to have
a break or a goto for each block.

Ironically, today, I see that far down at the bottom of the article,
under the code samples, there's a little block called Code Discussion.
And in it, it includes the following:

----------------------------------------------------------------------
Although fall through from one case label to another is not supported,
it is allowed to stack case labels, for example:
case 0:
case 1:
// do something;
----------------------------------------------------------------------
Sure you can

So I see, as others have pointed out. Until today, I couldn't find the
documentation that said a case could fall through as long *as it
contained no code*. What I did get was compiler errors that said you
couldn't fall through to the next case. In the scenario I was using, I
had a case that I wanted to do one thing, and then fall through to the
next case. Obviously, that's not allowed, but a code-less fall-through
is. It's enough to make me happy.
<CounterRant>
Couldn't you ask the question in a civilized fashion before ASSuming that this was the case?
</CounterRant>

I placed the rant in <RANT> </RANT> so that you'd know that I knew it
was a rant, and to set it off from the civilized portion of the post.
In my *personal* opinion, there's almost always a better way to code
than relying on a goto, and that has (so far) always been true. I'm not
an absolutist; there's an exception to every rule. I was just shocked
that -- based on the documentation in the help files -- it seemed that
they were forcing you to use it.

And I don't think I was assuming anything. I think that I was drawing a
reasonable conclusion based on the information I could find. An
assumption would have been made without having done any research at
all.
switch(student.Grade)
{
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
school = "Elementary";
break;
case "7":
case "8":
case "9":
school = "Junior High";
break;
default:
school = "High School";
break;
}

A little more verbose, but, the same concept.

Agreed. And more than suitable for my purposes. It's actually what I
expected it should look like; but in C, I believe a case can fall
through even if it has code. That was where my confusion came from.

I have to say that I'm not sorry to see that feature gone, tho. I'd bet
it's a source of many subtle bugs.
There was a recent thread on this topic. Feel free to look it up

Sure. Was it in this particular forum? If so, what keywords would you
suggest I use to find the specific thread you have in mind? I'm using
the Google newsreader.
They chose to allow advanced developers the chance to optimize their code when the situation
warranted it, rather than forcing us all to walk "The One True Path".

Bill

That's a reasonable conclusion, given that there is no "One True Path".
I'm just surprised they'd provide you with a construct that encourages
spaghetti code.

Just out of curiosity--did C# drop any keywords that were common to C
and C#? I know that it doesn't support malloc and delete. Are there any
more that were dropped?

Thanks very much for your reply!
 
Also, I notice that they added full support for goto--according to the
C# language reference, you can label lines and then use goto to
transfer execution to that line. To me, this smacks of old unstructured
BASIC code. Does anyone use this functionality in production code?
Under what circumstances do you find it useful, if at all?

This was debated recently.

(1) goto is frequent in machine-generated code, where you have a program
that writes other programs, using algorithms similar to those used by a
compiler. The designers of C# wanted to leave this option open.

(2) There are some algorithms that come out less repetitious with goto.
See:
http://www.stevemcconnell.com/ccgoto.htm

As a computer science professor, I worry that the younger generation has
been taught that goto is unmitigated evil. It isn't. Meanwhile, many of
the people who hate goto (because it's error-prone) love pointers (which are
error-prone in almost exactly the same way). We've traded spaghetti code
for spaghetti data structures.
 
<snip>

First, let me apologize if I came across ass an A**Hole.
I re-read my reply to you and I could have phrase stuff better.
<Snip poorly writen documentation on switch>
That documentation could definitely be more clear.
It does look like you need to JUMP after every case.

Agreed. And more than suitable for my purposes. It's actually what I
expected it should look like; but in C, I believe a case can fall
through even if it has code. That was where my confusion came from.

The 'switch' statement is taken almost exactly from C.
The designers of C# , I beleive, were attempting to prevent common errors related to fallthrough. So
they decided to make fallthrough illegal. BUT, they didn't remove the need for a 'break'; I guess
they were afraid that C programmers would misunderstand the meaning of a switch statement without
breaks in it. As a whole, switch could have better syntax than it does now.
I have to say that I'm not sorry to see that feature gone, tho. I'd bet
it's a source of many subtle bugs.
Yup


Sure. Was it in this particular forum? If so, what keywords would you
suggest I use to find the specific thread you have in mind? I'm using
the Google newsreader.

"Are gotos truly evil?" in this newsgroup around mid September
That's a reasonable conclusion, given that there is no "One True Path".
I'm just surprised they'd provide you with a construct that encourages
spaghetti code.

It's use is discouraged by most deveopers, but ocasionally it can come in handy
Just out of curiosity--did C# drop any keywords that were common to C
and C#? I know that it doesn't support malloc and delete. Are there any
more that were dropped?

structs and classes are different critters from their C/C++ brethren.
In C++ a struct is basically a class with everything public by default.

In C# classes exhibit reference semantics whereas structs exhibit value semantics.
This is a common cause of misunderstanding to C++ programmers.

Also strings in C# are immutable which is always a source of frustration if you are expecting
modifiable strings.


Good luck
Bill
 
Mike said:
switch(student.Grade) {
case "1", "2", "3", "4", "5", "6":
school = "Elementary";
break;
case "7", "8", "9":
school = "Junior High";
break;
default:
school = "High School";
break;
}

In addition to the many fall-through-switch solutions posted, what about
the readable, modular and error-checking:

public static string GradeToString(int grade) {
if ( grade >= 1 ) {
if ( grade <= 6 )
return "Elementary";
else if ( grade <= 9 )
return "Junior High";
else if ( grade <= SOMECONSTANT )
return "High School";
}
throw new InvalidArgument(
string.format("invalid grade: {0}", grade), "grade");
}
GradeToString(student.Grade);
Instead, I have to do this:

No, there are lots of other options.
<RANT>A frickin' GOTO!!!! What in the heck were they thinking?! I
thought we were supposed to be moving AWAY from spaghetti
code!!!</RANT>

You will probably perform better if you keep calm ;)
Also, I notice that they added full support for goto--according to the
C# language reference, you can label lines and then use goto to
transfer execution to that line. To me, this smacks of old unstructured
BASIC code. Does anyone use this functionality in production code?

If they do, why not let them? people make bugs with whatever tools they
have available :)
Under what circumstances do you find it useful, if at all? I guess I'm
just trying to figure out how Microsoft justified including a keyword
that seems to be pretty universally loathed in a brand new language
that's designed to be object oriented (and thereby inherently
structured).

See the much referred to thread on goto in C#.

There really isn't much harm in having it -- it can't bite you if you
don't use it :)
 
Michael A. Covington said:
This was debated recently.

(1) goto is frequent in machine-generated code, where you have a program
that writes other programs, using algorithms similar to those used by a
compiler. The designers of C# wanted to leave this option open.

I might note that almost every compiler-compiler(or parser generator) I've
used uses goto, wiht the exception of one recursive-descent parser
generator.
(2) There are some algorithms that come out less repetitious with goto.
See:
http://www.stevemcconnell.com/ccgoto.htm

As a computer science professor, I worry that the younger generation has
been taught that goto is unmitigated evil. It isn't. Meanwhile, many of
the people who hate goto (because it's error-prone) love pointers (which
are error-prone in almost exactly the same way). We've traded spaghetti
code for spaghetti data structures.

Its not just the younger generation, I don't think, I had a professor in her
50's who insisted goto is strictly evil. Those were pretty much the words
she used.
 
Back
Top