C# – Why was the statement (j++); forbidden

cexpressionlanguage-designparenthesessyntax

The following code is wrong (see it on ideone):

public class Test
{
    public static void Main()
    {
        int j = 5;
        (j++);      // if we remove the "(" and ")" then this compiles fine.
    }
}

error CS0201: Only assignment, call, increment, decrement, await, and
new object expressions can be used as a statement

  1. Why does the code compile when we remove the parentheses?
  2. Why does it not compile with the parentheses?
  3. Why was C# designed that way?

Best Answer

Deep insights appreciated.

I shall do my best.

As other answers have noted, what's going on here is the compiler is detecting that an expression is being used as a statement. In many languages -- C, JavaScript, and many others -- it is perfectly legal to use an expression as a statement. 2 + 2; is legal in these languages, even though this is a statement that has no effect. Some expressions are useful only for their values, some expressions are useful only for their side effects (such as a call to a void returning method) and some expressions, unfortunately, are useful for both. (Like increment.)

Point being: statements that consist only of expressions are almost certainly errors unless those expressions are typically thought of as more useful for their side effects than their values. C# designers wished to find a middle ground, by allowing expressions that were generally thought of as side-effecting, while disallowing those that are also typically thought of as useful for their values. The set of expressions they identified in C# 1.0 were increments, decrements, method calls, assignments, and somewhat controversially, constructor invocations.


ASIDE: One normally thinks of an object construction as being used for the value it produces, not for the side effect of the construction; in my opinion allowing new Foo(); is a bit of a misfeature. In particular, I've seen this pattern in real-world code that caused a security defect:

catch(FooException ex) { new BarException(ex); } 

It can be surprisingly hard to spot this defect if the code is complicated.


The compiler therefore works to detect all statements that consist of expressions that are not on that list. In particular, parenthesized expressions are identified as just that -- parenthesized expressions. They are not on the list of "allowed as statement expressions", so they are disallowed.

All of this is in service of a design principle of the C# language. If you typed (x++); you were probably doing something wrong. This is probably a typo for M(x++); or some just thing. Remember, the attitude of the C# compiler team is not "can we figure out some way to make this work?" The attitude of the C# compiler team is "if plausible code looks like a likely mistake, let's inform the developer". C# developers like that attitude.

Now, all that said, there actually are a few odd cases where the C# specification does imply or state outright that parentheses are disallowed but the C# compiler allows them anyways. In almost all those cases the minor discrepancy between the specified behaviour and the allowed behaviour is completely harmless, so the compiler writers have never fixed these small bugs. You can read about those here:

Is there a difference between return myVar vs. return (myVar)?