Labels and GOTO
s are considered bad practice and as far as I know there is no reason to use it in C#.
What is the use of labels in C#?
Labels and GOTO
s are considered bad practice and as far as I know there is no reason to use it in C#.
What is the use of labels in C#?
There is nothing wrong with labels and goto's in themselves. The problem is that people tend to abuse them which does create a problem.
Typical use of a label
OperationStart:
if ( !TrySomeOperation() ) {
if ( MaybeFixOperation() ) {
goto OperationStart;
}
}
You'd need to make some assertions that you couldn't hit an infitite loop, but given a reasonable set of guarantees there's nothing inherently wrong with this code.
Just because they are a disreputable practice, doesn't mean to should close off any possibility of using them. While they may never actually be required, they are occasionally the best way to go.
When you are implementing a small finite state machine you can use a label for each state and goto for state transitions. This is one of the standard methods of implanting finite state machines and can lead to clear code, provided there is a diagram of the state machine in a document that the code comments point to.
Sometimes the problem domain contains lots of state machiens, (e.g. telecoms protocols are often defined by finite state machines), most of the time you don’t see finite state machine often.
Gotos and labels are also very useful for machine-generated code, if you are writing a simple compiler that outputs C# you may be very glad of them.
Code generators sometimes use labels and gotos. It can simplify the code generation logic in some cases. Goto statements are generally shunned for readability reasons, but if the code is not intended to be read then that is a moot point.
I have also seen cases where a decompiler gets confused enough by the IL and outputs goto statements instead of the well crafted sequence of instructions that a human would have conjured. If goto statements were not legal then the decompiler might have to completely punt on that section of code. This way, at least, it can generate something that can be round-tripped.
Why is it there?
The reason is actually pretty simple. Assembler and IL don't support advanced instructions like for
, do
, break
, continue
and while
. Implicitly, code that loops (or more generally: branches) is compiled to branches. goto
and label
is a very literal branch.
Note that you simply cannot implement all the contraptions that I can think of easily without a 'goto'- even though there are usually better alternatives (at this point I'd like to point out that there are Design Patterns like the State pattern
).
If you design a language like C#, which is kind-of the "high level assembler for IL", it only makes sense to support at least everything there is in IL. Here, branch / label is the low-level construct, and goto / label is the C# projection (with scope added as high-level construct).
From the compiler POV
Eventually if you go down to how a compiler works, there's a difference in predictable code and unpredictable code. The optimizing part of a compiler spends a tremendous amount of effort into normalizing the constructions you're using in your code. Once normalized, it's optimized using patterns.
Herein lies the problem. If you have a while
loop, a for
loop or a foreach
loop, it will definitely generate a normalized pattern. After all, loops are the number one thing in your code that can be optimized. However, if you're using strange branches, they won't be optimized - simply because it won't be normalized to a standardized pattern and therefore won't be picked up by the pattern matcher.
This comment is not just about predictability of code patterns - it's also about predictability of data flow. Again, if it's predictable, your compiler can do more than if it's not. In various cases, constructs like break
and continue
will also lead to more unpredictable branches; labels and goto
will just get you there more easily. The result is the same: your performance will suffer if this occurs.
So while it's true that all compilers change loops into branches of a specific form. The IL compiler is a SSA compiler, just like LLVM. This video of Chandler explains a thing or two about how this works: https://www.youtube.com/watch?v=FnGCDLhaxKU
I think it was a marketing decision..
Microsoft wants all kinds of developers using their C# language, and if you add labels, it makes transition for some programmers easier. It also makes it easier to port old code to their language...
Labels without goto
are useless, they do nothing.
Using goto
is considered a bad practice. But there is a case where it can't be avoided: breaking out of nested loops:
foreach(...) {
foreach(...) {
if(...) {
goto OuterLabel;
}
}
}
OuterLabel:
In such a case using the break
statement would just break the most inner loop.
If (audience.LikesGoTo == true) { goto LabelThatSupportGoTo; } else { goto LabelForRejectGoTo; }
I read somewhere, goto in most cases should just be use for jumping forward, so most likely just for early loop terminations and for continuing the outer loop since there are no labeled loops in C# (unlike Java). And there are some algorithms that can be elegantly expressed with goto than doing it the structured way.
It's hard to do switch statements without them.
Sometimes a well placed 'goto' is more elegant/readable than other techniques. Putting 'goto's around when they're not needed is certainly a bad practice. As always, each situation should be judged carefully.
For example, 'goto's can be nice when your function needs to do cleanups in case it fails. You place a label at the end of the function, where you do your cleanup, then 'goto' it in case of a failure.
Nevertheless, 'goto's have become less useful in C# than in C. For example, proper usage of exception handling can obviate the need of 'goto' in some scenarios.
The use of labels is to support goto
. Bad as goto
may be, if you have goto
in the language, then you need labels. Without goto
, labels are indeed useless in C#.
While in principle I believe that there are legitimate uses for the goto
statement, in practice I've been developing in C# since it was first released and I didn't know it had a goto
statement until now.