32

I recently came across this code in a project - which I assume was there by mistake:

if(condition)
{
   //Whatever...
};

Note the semi colon after the closing brace.

Does anyone know what the effect of this is?

I assume it does not have any effect, but would have thought it would have caused a compiler error.

scharette
  • 9,437
  • 8
  • 33
  • 67
Alex
  • 3,730
  • 9
  • 43
  • 94
  • 2
    Did you try to compile it? What was the result? – Robert Columbia Jul 10 '18 at 12:42
  • 31
    It's just an unnecessary line termination - `if(true) {};;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;` will compile – stuartd Jul 10 '18 at 12:42
  • 1
    It's just an empty statement. – Lee Jul 10 '18 at 12:42
  • 4
    It's an empty statement. It does nothing. – Some programmer dude Jul 10 '18 at 12:42
  • I wonder why simple questions always get down voted at start... Instead of the cliche _There is no bad questions_, let's just say that _simple_ doesn't mean _bad_. – scharette Jul 10 '18 at 19:09
  • 3
    Note that if you had written `if(condition);` then you *would* have gotten a warning from the compiler saying that the empty statement was likely a mistake; this is because `if(condition); DoIt();` appears to the novice programmer to run `DoIt()` conditionally but actually runs it non-conditionally. The compiler authors could have done the same for `if(condition){};` but that mistake is far more likely to be harmless because it does not modify the meaning of the program. – Eric Lippert Jul 10 '18 at 19:27
  • 3
    Note also that C# allows a trailing semi after a class declaration, and ignores it. In that case, this is simply a courtesy to C++ programmers who are used to typing semis after classes; C++ requires this. – Eric Lippert Jul 10 '18 at 19:28
  • At one point, a certain fairly large tech company tried to increase productivity in their developers by counting their lines of code and using it as a way of evaluating the developer. Developers eventually realized that there was a program which was simply counting their semi-colons. Devs then started adding extra semi-colons to their code in order to increase their evaluations. Maybe the semi-colon in this snippet doesn't do nothing after all, Maybe it is there to help the dev get _paid_. – nurdyguy Jul 10 '18 at 19:54

3 Answers3

34

This is a simple question with a simple answer, but I just wanted to add something relevant. Often people understand that it does nothing and particularly for the case that you presented, the semi-colon is an unnecessary line termination.

But what is the rationale behind it ?

Actually, those empty statements are allowed for statement like these:

 // Use an empty statement as the body of the while-loop.
while (Method())
        ;

I agree that it does nothing. But it can help certain loops conform to the syntactic requirements of the language and I think this is what people should understand from it. As other said, I agree you can remove it, I just wanted to underline why C# allows it.

Further clarification

An empty statement is used when you don't need to perform an operation where a statement is required. It simply transfers control to the end point of the statement. It has no effect at all, it is pure syntactic sugar.

As stated by @PaulF, in the example above, you could use an empty block ({}) instead. It would be totally valid and have the same effect.

Again, it all comes down to style. You don't need it, but it can certainly help you conform to whatever rules of your coding environments.

Common use-cases (where one could see empty statements)

  • While loop with empty body (same case that I underlined above)

    void ProcessMessages()
    {
        while (ProcessMessage())
            ; // Statement needed here.
    }
    
  • goto statements (rarely use but still valid)

    void F()
    {
        //...
        if (done) goto exit;
    //...
    exit:
        ; // Statement needed here.
    }
    

    From MSDN

  • Class declaration (Props to @EricLippert for bringing this one)

    class SomeClass
    {
        ...
    };
    

Note that in this case, as stated by @EricLippert in the comments section, this is simply a courtesy to C++ programmers who are used to typing semis after classes; C++ requires this.

Even though the general use of empty statements is debatable mainly because of the confusion they can bring, in my opinion, syntactically speaking they have a place in C#. We must not forget that C# is an increment of C++ (which mostly explain the # aka. four "+" symbols in a two-by-two grid) and for historical reasons, allowing empty statements was facilitating the transition.

scharette
  • 9,437
  • 8
  • 33
  • 67
  • That doesn't really explain why C# allows it as _"while (Method()) {}"_ is syntactically valid & has similar effect. – PaulF Jul 10 '18 at 12:54
  • @PaulF Naming your C# methods _"my_methods"_ is syntactically valid & has similar effect also. It all comes down to style. – scharette Jul 10 '18 at 12:56
  • I think the rationale behind it being allowed is that it is much simpler (syntax wise) to allow for empty statements than it is to disallow them. Just as it is valid to randomly embed code anywhere in braces or even have pairs of braces _"{}"_ containing nothing between statements. But I do agree it is (or can be) a matter of style. Upvoted with your further clarification. – PaulF Jul 10 '18 at 13:07
  • 2
    I believe "scope" is a much preferable term over "block" in the case of C#, given the implications of curly braces as far as scoping goes. Implicit scope + `nop` statement = more than just a styling concern though, IMO. You could be tempted to blindly just remove that semicolon, and then be surprised that you just introduced a bug because the next statement is now the implicit scope. – Mathieu Guindon Jul 10 '18 at 19:07
  • 1
    @PaulF: As someone who has written many parsers, there is no "simplicity" argument to be made; empty statements do not simplify parsers. My opinion is that empty statements are a misfeature that should never have been added to C# or for that matter, C. All the empty statement does is produce an opportunity for accidentally putting a semi in a place where it is hard to see but changes the meaning of a program. – Eric Lippert Jul 10 '18 at 19:16
  • 1
    @PaulF: In fact, there is a simplicity argument to be made for *not* having the feature. Not only is the parser complicated slightly by needing to parse the empty statement, **the parser is complicated even more by the need to add heuristics that detect and warn about incorrect uses of the empty statement**. When incorrect usages outnumber correct usages, you have a bad feature that should be removed. – Eric Lippert Jul 10 '18 at 19:17
  • 5
    @MathieuGuindon: No no no, "scope" has a very specific meaning in C#. **Scope is the region of program text in which a particular entity can be accessed by its unqualified name**. The correct way to think about it is that a *block statement* introduces a *local variable declaration space*, and that the *scope* of local variables immediately within that declaration space is *the text of the block*. These things are obviously *strongly related*, but they are logically different, so do not conflate them. – Eric Lippert Jul 10 '18 at 19:19
  • @EricLippert Thanks for your insight on parsers, I hate the old justification _it's there because it's simpler_. I'm pretty sure there is rationale behind every (or almost every) features of a language. I understand that their purpose is easily debatable but they're not as _useless_ as people may think. This was actually the basis of my answer. – scharette Jul 10 '18 at 19:24
  • @EricLippert thanks for the clarification - I really meant the *implicit local variable declaration space* ..though calling that a "scope" was conveniently shorter! =) – Mathieu Guindon Jul 10 '18 at 19:32
  • @MathieuGuindon: Moreover: A block statement always introduces a scope, but there are scopes that are not introduced by block statements. The member scope is introduced by the `{}` of a type declaration, which is not a *block statement*. Lambdas introduce scopes even if they do not contain blocks. Generic type parameters of types are scoped to the *entire* text of the class, not just to the region within `{}`. The scoping rules for the `foreach` loop variable are complicated and changed in C# 5. And so on. – Eric Lippert Jul 10 '18 at 19:34
  • @EricLippert: I just didn't think the ability to have an empty statement as opposed to an empty block for while loops was a particularly good rationale for allowing them. I, too, have written quite a few parsers over the years & never had an issue of allowing empty blocks or empty statements - not for complex languages though. I do agree that the empty statement does give the opportunity for hard to spot errors (as does the comma operator in C/C++). – PaulF Jul 11 '18 at 09:46
  • @PaulF: Indeed; it's not that it's *hard*. But like all features, the empty statement needs to be designed, implemented, tested and documented; users need to be educated about it; warnings need to be written to detect its misuse; all this effort is for *what return?* None! There's no benefit whatsoever to this work. The feature is *stealing time and attention away from more important features*. – Eric Lippert Jul 11 '18 at 16:15
  • @EricLippert I added an edit. My goal is not to start a debate with you. After reading through your comments I see empty statements differently. But I wouldn't say that there is no benefits at all. It allows for similar syntax of C++ as I said in my answer which can facilitate transition from C/C++ . I think this is relevant somehow. Maybe not for all the work that have been done to allow it, but at least its not _nothing_. – scharette Jul 11 '18 at 16:19
  • 1
    @scharette: Indeed, the primary reason for the feature in the first place is similarity to C and C++. But the feature is a bad feature in C too! It should never have been added to C, and given that it was, it should not have been copied into C#. After all, C# was intended to be an *improvement* on C, not a slavish copy. There are many C misfeatures that were never added to C#; the comma operator as noted in the comment above, switch fallthrough, and so on. Empty statements could have been removed from C# in the original design but we're stuck with them now. – Eric Lippert Jul 11 '18 at 16:23
  • @EricLippert _But the feature is a bad feature in C too! It should never have been added to C_ There I can entirely agree with you. But that's a long time ago and people got used to it. I mean they're even allowed in Java. C# was actually Java's competition from Microsoft. This is 100% speculation, but I just think that Microsoft, among other reasons, did that to accommodate their C/C++ community in order not to loose this giant pool of programmers. – scharette Jul 11 '18 at 16:29
  • @scharette: The relationship between Sun, Microsoft, Java, C# and C is long, complicated, and does not fit into a short comment. There are a variety of strategic and tactical reasons why C# and .NET made sense in the business environment of the time, but from a *design* perspective, C# was not intended to be a response to Java; it was intended to be an improved C++. Of course we learned from the mistakes of Java; it would be foolish not to. But C# was not intended to be "Java with the stupid parts removed" like some said at the time of its design. – Eric Lippert Jul 11 '18 at 16:44
  • 1
    This is 100% speculation too - but I am pretty sure that given a choice between Java & C#, empty statements are going to be the least of a C++ programmers concerns when deciding on the language to use for a new project. – PaulF Jul 11 '18 at 16:45
  • @PaulF Not a deciding factor I agree. But certainly a _nice-to-have_ though. – scharette Jul 13 '18 at 19:53
  • I think the effort of typing 1 more character {} instead of ; - doesn't even warrant getting on the nice to have list - it's not as if the majority of code consists of while loops with empty bodies. – PaulF Jul 14 '18 at 10:30
  • @PaulF that will be my last comment on this, but you're clearly not getting the point. I'm not saying its easier to type. Everybody know it has nothing to do with programmer's efficiency. I'm just saying that some people prefer the semi style-wise. You clearly don't and its fine because they let you use `{}` instead. – scharette Jul 14 '18 at 13:14
17

It doesn't seem to have any effect, though I wouldn't recommend writing code that way.

In the event that you ever want to add an else or else if after the ;, it won't compile.

Ex:

if(5>1) {
  //whatever
}; else {
  //whatever
}

This will not compile (note the ; before else)

Isaac Abramowitz
  • 542
  • 5
  • 17
  • 3
    What you say isn't wrong, but you're changing the focus of the question. It failse to compile because `else` can't find an `if` that precedes it. You added the `else`, OP did not. The question is why the semicolon **at the end** is allowed, not if there are cases where a semicolon **in the middle** will cause issues. – Flater Jul 11 '18 at 07:28
8

That is something that Visual Studio will compile as valid syntax for an empty statement, as it is just a statement termination. Your code will compile and the extra ; will not be an issue.

It can be deleted to clean up the code if you want to, but leaving it in will not cause any adverse effect.

Hope this helps.

Fuzzybear
  • 1,388
  • 2
  • 25
  • 42