Search code examples
c#compiler-errorsshort-circuiting

Using short circuits function calls in statements in C# is not allowed?


I am attempting to use short circuiting between two function calls. Take for example this code:

private void BubbleDown(Graph.Vertex item)
{
    BubbleDownLeft(item) || BubbleDownRight(item);
}

Where BubbleDownLeft and BubbleDownRight both return a bool. This throws the following error:

Error CS0201 - Only assignment, call, increment, decrement, and new object expressions can be used as a statement

I know I can easily rewrite the function to use an if statement (but that's not as pretty) or even just assign it to a value I don't use:

private void BubbleDown(Graph.Vertex item)
{
    bool ignoreMe = BubbleDownLeft(item) || BubbleDownRight(item);
}

So why is my first coding example an error rather than valid or perhaps just a warning?


Solution

  • The suggested code doesn't make sense for a computer. When you ask it to BubbleDown() you tell it to either BubbleDownLeft() or BubbleDownRight() but also to ignore the result. The compiler has no incentive to use short-circuit evaluation since the result is ignored anyway. This short circuit-evaluation is what kicks in if this was an if statement.

    In a comment you state:

    I'll agree the extraneous ignoreMe is worse than an if, but the original is easily read. It clearly says that bubbleDown is the result of either the left or the right. Going with the a, b, c, d, e, example, you would have to put if (!(a() || b() || c() || d())) e()) which would look like e() is the goal, but really it's a 5-branching path where the first path to succeed is taken.

    This clearly indicates that you want the short-circuit evaluation, and your options for getting this are either to change return type and do:

    private bool BubbleDown(Graph.Vertex item)
    {
        return BubbleDownLeft(item) || BubbleDownRight(item);
    }
    

    Or you could opt for an if statment with an empty block. Note the ; after the if statement:

    private void BubbleDown(Graph.Vertex item)
    {
       if (BubbleDownLeft(item) || BubbleDownRight(item)) ;
    }
    

    I think I would prefer the first, and then simply ignore the return value at the point where your calling BubbleDown(), or actually verify that it actually has executed any of the options truthfully.