what
This is the coding style used for languages with many implicit type conversions (friendly by the name of Yoda from the Star Wars character due to his OSV word order). Sometimes it is even forcibly applied and required along the project guidelines to prevent some errors from typos. Different languages have different variations and extensions of this style, but I will limit this answer to C and C #.
Why yes
For example, in C you can write:
int a = CalculateValue(); if (a = CalculateAnotherValue()) { }
This code will assign a
value returned from CalculateValue()
, after which it will overwrite the value with the result CalculateAnotherValue()
, and if it is not zero, it will execute the code. This is probably not what is intended, but the assignment in the if
is a mistake. In your example, using NULL
, you could have:
if (pBuffer = NULL)
Again, perhaps this is not what you want (and this is a pretty common mistake), you will assign NULL to the pointer, and the condition will always be false. If you write:
if (NULL = pBuffer)
It will not compile (because you cannot assign a value to a literal) and you will get a compile-time error.
This kind of compile-time check is not the only reason to use this coding style, see this C # code (very general):
if (text != null && text.Equals("something", StringComparison.InvariantCulture) DoSomething();
It can be reduced to:
if ("something".Equals(text, StringComparison.InvariantCulture)) DoSomething();
Why not
In C #, this usually doesn't matter. This is a practice inherited from C / C ++. Since C # expressions are not automatically converted to bool
, the following code will not compile:
if (Request.QueryString["PartnerID"] = null)
Then this practice is useless in C # (@IlianPinzon pointed out an exception in the comments), it did not use anything about performance to avoid such errors.
In the last example, in the "Why Yes" section, the readability problem, write "something".Equals(text)
is to say "if the guy is happy" and not "if the guy is happy."
Performance
Starting with these functions:
static bool TestRight(object value) { return value == null; } static bool TestLeft(object value) { return null == value; }
They produce the 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 are simply replaced, but the order of its operands does not change the behavior of ceq
. Even if you override the Equals()
method, the JIT compiler will generate the same assembly code for both expressions (because the comparison will always be done using Equals()
, NULL
is unsigned).
Things can be more complicated if the comparison is related to custom equality matching, in this case there is no rule, and this will depend on the effective implementation of op_Equals
. 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
, execution will be slightly faster (because MyType.Equals()
will not even be called), but this performance increase is very small: you save one comparison, several jumps and a virtual function call. In addition, you can rewrite a function faster in the opposite case (in case you really think about it).
Here's a little test in which MyType.Equals(object)
just returns true
for any non- NULL
parameter. The test will Int32.MaxValue
times:
Operation Total time (ms)
lhs == null 10521
null == lhs 2346
It seems that the “optimized” version, which avoids the unnecessary call to Equals()
, is five times faster, but note that the number of loops is very large and the actual implementation of Equals()
empty, a true implementation will reduce the relative overhead of calling the function (and, maybe you will have something else than this micro-optimization ). For system classes, you cannot rely on this information, for example, String.Equals()
will always be called by operators (it does not matter for order), but you cannot assume that one code path is faster, and this fact will not change in future versions (or for different CPU architectures).