3Dave
3Dave

Reputation: 29051

pre/post-increment in conditional skipped by short-circuit evaluation

So, if I have an expression like:

if (obj != null && i++ % divisor == 0)
{
....
}

and obj is null, then i is never incremented. If I use

i++; 
if (obj != null && i % divisor == 0)
{
....
}

instead, then, of course, i is incremented.

Is this by design? I understand short-circuit evaluation from an optimization point of view, but I had (incorrectly) assumed that the compiler would recognize the post-increment expression and evaluate it regardless.

(If this is in the spec, I couldn't find it - just looking for some (gasp) opinions here.)

Update

Here's the actual code.

    private int _frameNumber = 0;

    private void simulator_OnFrameEnd(object sender, System.EventArgs e)
    {
        _frameNumber++; 

        if (_visualizer != null && _frameNumber % _config.VisualizerUpdateFrequency == 0)
        {
            var field = _simulator.GetField(_config.PreviewField);

            _visualizer.Update(field, _simulator.FrameTime);
        }

        if (_frameNumber % _config.OptimizerRegridFrequency == 0)
        {
            _simulator.UpdateFieldGrids();

        }

    }

Upvotes: 2

Views: 387

Answers (5)

p.s.w.g
p.s.w.g

Reputation: 149050

Yes, it's by design. The left side is never evaluated if the right side evaluates to false, including any side effects that might occur (such as the increment)

The operation x && y corresponds to the operation x & y, except that y is evaluated only if x is true

—source MSDN

Yes that's an older version of the documentation, but the language is clearer, IMO.

If you want the increment to be evaluated use this:

if (_visualizer != null & _frameNumber++ % _config.VisualizerUpdateFrequency == 0)
{
    ...
}

If you want to perform the increment even when visualizer == null but not the modulus:

var _prevFrameNumber = _frameNumber++;
if (_visualizer != null && _prevFrameNumber % _config.VisualizerUpdateFrequency == 0)
{
    ...
}

Upvotes: 1

Lee
Lee

Reputation: 144206

Yes, this is by design. From the specification:

7.12.1 Boolean conditional logical operators

The operation x && y is evaluated as (bool)x ? (bool)y : false. In other words, x is first evaluated and converted to type bool . Then, if x is true , y is evaluated and converted to type bool , and this becomes the result of the operation. Otherwise, the result of the operation is false

In your code, y is i++ % divisor == 0 so i++ will not be executed if obj is null.

Upvotes: 4

waka
waka

Reputation: 3417

The frameNumber is not incremented because _visualizer != null returns false. So the code doesn't even bother to check/excecute the increment and modulo operation.

If you'd switch the checks around (ie if (_frameNumber++ % 5 == 0 && _visualizer != null)) then _frameNumber gets incremented... because the operaion actually is executed.

So yes: This is wanted behavior and it is by design.

Upvotes: 2

FishBasketGordo
FishBasketGordo

Reputation: 23142

It is most definitely by design. MSDN states:

The operation x && y corresponds to the operation x & y except that if x is false, y is not evaluated, because the result of the AND operation is false no matter what the value of y is. This is known as "short-circuit" evaluation.

So, it doesn't matter what your statement is, whether it has a post-increment or not, it won't be evaluated if it's short-circuited.

Upvotes: 6

Oren
Oren

Reputation: 3248

The post-increment is only post evaluation of the statement. Since the statement is never evaluated (it's short circuited) it's skipped.

A more visual way to think of it is to imagine the if statement as being nested:

if (obj != null)
{
   if (i++ % divisor == 0)
   {
   ...
   }
}

Here we see immediately that i will not be incremented. Similarly when an if statement is short circuited the behaviour is similar to the above and the post increment is not queued.

Upvotes: 6

Related Questions