What
It's a coding style in use for languages with many implicit type conversions (friendly named Yoda from Star Wars character because of his OSV word order). Sometimes it's even enforced and required by project guide-lines to prevent some kind of errors derived from typos. Different languages have different variations and extensions of this style but I'll limit this answer to C and C#.
Why Yes
For example in C you can write:
int a = CalculateValue();
if (a = CalculateAnotherValue()) {
/* Do something */
}
This code will assign to a
the value returned from CalculateValue()
then it'll overwrite the value with the result of CalculateAnotherValue()
and if it's not zero then it'll execute the code. Probably it's not what intended to do and the assignment in the if
expression is a mistake. From your example with NULL
then you may have:
if (pBuffer = NULL)
Again probably it's not what you want (and it's a quite common mistake), you'll assign NULL to the pointer and the condition will be always false. If you write:
if (NULL = pBuffer)
It won't compile (because you can't assign a value to a literal) and you'll get a compile-time error.
This kind of compile time checks are not the only reason to use this coding style, look this C# (very common) code:
if (text != null && text.Equals("something", StringComparison.InvariantCulture)
DoSomething();
It could be contracted to:
if ("something".Equals(text, StringComparison.InvariantCulture))
DoSomething();
Why No
In C# usually it doesn't matter. It's a practice inherited from C/C++. Because in C# expressions are not converted automatically to bool
then following code won't compile:
if (Request.QueryString["PartnerID"] = null)
Then this practice is useless in C# (with the exception pointed out by @IlianPinzon in the comments), nothing about performance it was used only to avoid such kind of mistakes.
About the last example in the Why yes section the problem is readability, to write "something".Equals(text)
is like to say "if happy is the guy" instead of "if the guy is happy".
Performance
Starting from these functions:
static bool TestRight(object value)
{ return value == null; }
static bool TestLeft(object value)
{ return null == value; }
They produce following IL:
.maxstack 2
.locals init ([0] bool CS$1$0000)
L_0000: nop
L_0001: ldnull
L_0002: ldarg.0
L_0003: ceq
L_0005: stloc.0
L_0006: br.s L_0008
L_0008: ldloc.0
L_0009: ret
The only difference is in lines L_0001 and L_0002, they're just swapped but order of its operands doesn't change the behavior of ceq
. Even if you override Equals()
method the JIT compiler will produce the same assembly code for both expressions (because the comparison will be always done by Equals()
, null
is typeless).
Things can be more complicated if the comparison involves a user defined equality comparer, in this case there is not a rule and it'll depend on the effective op_Equals
implementation. For example this ==
implementation:
public static bool operator==(MyType lhs, MyType rhs)
{
if (Object.ReferenceEquals(lhs, rhs))
return true;
if (Object.ReferenceEquals(lhs, null))
return false;
return lhs.Equals(rhs);
}
In this case if the first operand is null
the execution will be slightly faster (because MyType.Equals()
won't be even called) but this performance gain is very small: you save one comparison, few jumps and a virtual function call. Moreover you can rewrite the function to be faster in the opposite case (in case you really matter about this).
Here a small test where MyType.Equals(object)
simply returns true
for any non null
parameter. The test will be looped Int32.MaxValue
times:
Operation Total time (ms)
lhs == null 10521
null == lhs 2346
It seems the "optimized" version that avoid unnecessary call to Equals()
is five times faster but note that the loop count is very high and actual implementation of Equals()
is empty, a true implementation will reduce the relative overhead of the function call (and probably you'll have something else than this micro-optimization to do). For system classes you can't rely on this details, for example String.Equals()
will be always called by operators (no matters the order) but you can't assume one code path is faster and this fact won't change in future versions of the framework (or for different CPU architectures).