Is Relying on && Short-Circuiting Safe in .Net

Is relying on && short-circuiting safe in .NET?

Yes. In C# && and || are short-circuiting and thus evaluates the right side only if the left side doesn't already determine the result. The operators & and | on the other hand don't short-circuit and always evaluate both sides.

The spec says:

The && and || operators are called the conditional logical operators. They are also called the “shortcircuiting” logical operators.

...

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

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.

(C# Language Specification Version 4.0 - 7.12 Conditional logical operators)

One interesting property of && and || is that they are short circuiting even if they don't operate on bools, but types where the user overloaded the operators & or | together with the true and false operator.

The operation x && y is evaluated as T.false((T)x) ? (T)x : T.&((T)x, y), where
T.false((T)x) is an invocation of the operator false declared in T, and T.&((T)x, y) is an invocation of the selected operator &. In addition, the value (T)x shall only be evaluated once.

In other words, x is first evaluated and converted to type T and operator false is invoked on the result to determine if x is definitely false.

Then, if x is definitely false, the result of the operation is the value previously computed for x converted to type T.

Otherwise, y is evaluated, and the selected operator & is invoked on the value previously computed for x converted to type T and the value computed for y to produce the result of the operation.

(C# Language Specification Version 4.0 - 7.12.2 User-defined conditional logical operators)

Short circuit with TryParse() and out variable reliable?

Is the access to foo really done after the TryParse which would
consider any changed value

Yes, this will be the case.

or the compiler can sometimes read the value before TryParse [because
of some optimizations] and therefore I cannot rely on this code.

No, it will not read foo before the call to Int32.TryParse; one being that the logical OR will always evaluate the left side and only evaluates the right side if it's necessary. two, it will not evaluate the right side first because the foo variable is not initialised at that point which would cause a compilation error (assuming it's a local variable).

.Net performance of short-circuiting operators for comparing a value type?

I would use the Or Assignment operator:

_stale |= added;

Or:

_stale |= _foos.Add(foo);

This operator is specifically designed for this purpose, which makes the intent clear (and will most likely be the best in terms of performance, as it's specifically designed for this purpose).

As for the actual performance, this level of micro-optimization is typically almost impossible to measure as any difference in performance is going to be so much smaller than the difference in your operations (the HashSet<T>.Add call) that clarity of code is far more important. You could build a test to measure this, but it is incredibly unlikely to be reliably different enough in terms of performance to matter.

Usage of '&' versus '&&'

& is a bitwise AND, meaning that it works at the bit level. && is a logical AND, meaning that it works at the boolean (true/false) level. Logical AND uses short-circuiting (if the first part is false, there's no use checking the second part) to prevent running excess code, whereas bitwise AND needs to operate on every bit to determine the result.

You should use logical AND (&&) because that's what you want, whereas & could potentially do the wrong thing. However, you would need to run the second method separately if you wanted to evaluate its side effects:

var check = CheckSomething();
bool IsValid = isValid && check;

Can I force my own short-circuiting in a method call?

Well, this is ugly but...

static bool NoNulls(params Func<object>[] funcs) {
for (int i = 0; i < funcs.Length; i++)
if (funcs[i]() == null) return false;

return true;
}

Then call it with:

if (NoNulls(() => obj,
() => obj.Parameters,
() => obj.Parameters.UserSettings)) {
// do something
}

Basically you're providing delegates to evaluate the values lazily, rather than the values themselves (as evaluating those values is what causes an exception).

I'm not saying it's nice, but it's there as an option...

EDIT: This actually (and accidentally) gets to the heart of what Dan was after, I think. All a method's arguments are evaluated before the method itself is executed. Using delegates effectively lets you delay that evaluation until the method needs to call the delegate to retrieve the value.

Can I include null-checking an object as another conditional in OR statement?

Yes, this is safe. || and && are short-circuiting operators. From the MSDN Library:

The conditional-OR operator (||) performs a logical-OR of its bool operands, but only evaluates its second operand if necessary.

The operation

x || y

corresponds to the operation

x | y

except that if x is true, y is not evaluated (because the result of the OR operation is true no matter what the value of y might be). This is known as "short-circuit" evaluation.

Is it safe to assume if-and statements will always break if the first condition is false?

MSDN states(https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators):

The conditional logical AND operator &&, also known as the "short-circuiting" logical AND operator, computes the logical AND of its operands. The result of x && y is true if both x and y evaluate to true. Otherwise, the result is false. If x evaluates to false, y is not evaluated.

So your assumption is correct. Though you should be careful when you use &:

The & operator computes the logical AND of its operands. The result of x & y is true if both x and y evaluate to true. Otherwise, the result is false.

The & operator evaluates both operands even if the left-hand operand evaluates to false, so that the operation result is false regardless of the value of the right-hand operand.

You might get unwanted evaluation when you use &.

Interlocked.CompareExchange short-circuit evaluation

Before performing the Interlocked operation and the allocation see if the target location is not null already. If yes, there is no need to try and initialize it.

if (Volatile.Read(ref target) == null) InitAtomically();

Why would a language NOT use Short-circuit evaluation?

Reasons NOT to use short-circuit evaluation:

  1. Because it will behave differently and produce different results if your functions, property Gets or operator methods have side-effects. And this may conflict with: A) Language Standards, B) previous versions of your language, or C) the default assumptions of your languages typical users. These are the reasons that VB has for not short-circuiting.

  2. Because you may want the compiler to have the freedom to reorder and prune expressions, operators and sub-expressions as it sees fit, rather than in the order that the user typed them in. These are the reasons that SQL has for not short-circuiting (or at least not in the way that most developers coming to SQL think it would). Thus SQL (and some other languages) may short-circuit, but only if it decides to and not necessarily in the order that you implicitly specified.

I am assuming here that you are asking about "automatic, implicit order-specific short-circuiting", which is what most developers expect from C,C++,C#,Java, etc. Both VB and SQL have ways to explicitly force order-specific short-circuiting. However, usually when people ask this question it's a "Do What I Meant" question; that is, they mean "why doesn't it Do What I Want?", as in, automatically short-circuit in the order that I wrote it.

Unassigned local variable and short-circuit evaluation

This can't be considered a bug but its an improvable feature. You are correct when you say that the compiler has enough information to know that the unassigned i is never used and therefore it should omit the compiler error.

Its improvable because, as a matter of fact, it has been improved; in VS 2015 the behavior of the compiler is the expected one : no compile time error. I can't say the same thing for previous versions of the compiler because I can't test them at the moment.

Funnily enough, neither VS 2015 or VS 2017 RC report an unreachable code warning at return i which seems a bit odd. if (true) will give this warning and if (true || ....) figures out correctly that i is not used, but the warning has been omitted for reasons I dont understand.

For more insight on why the behavior was changed, check out this answer. I knew this question rung a bell...I asked a similar one a couple years ago myself ;).



Related Topics



Leave a reply



Submit