Benefits of using the conditional ?: (ternary) operator - c#

What are the benefits and drawbacks of the ?: operator as opposed to the standard if-else statement. The obvious ones being:
Conditional ?: Operator
Shorter and more concise when dealing with direct value comparisons and assignments
Doesn't seem to be as flexible as the if/else construct
Standard If/Else
Can be applied to more situations (such as function calls)
Often are unnecessarily long
Readability seems to vary for each depending on the statement. For a little while after first being exposed to the ?: operator, it took me some time to digest exactly how it worked. Would you recommend using it wherever possible, or sticking to if/else given that I work with many non-programmers?

I would basically recommend using it only when the resulting statement is extremely short and represents a significant increase in conciseness over the if/else equivalent without sacrificing readability.
Good example:
int result = Check() ? 1 : 0;
Bad example:
int result = FirstCheck() ? 1 : SecondCheck() ? 1 : ThirdCheck() ? 1 : 0;

This is pretty much covered by the other answers, but "it's an expression" doesn't really explain why that is so useful...
In languages like C++ and C#, you can define local readonly fields (within a method body) using them. This is not possible with a conventional if/then statement because the value of a readonly field has to be assigned within that single statement:
readonly int speed = (shiftKeyDown) ? 10 : 1;
is not the same as:
readonly int speed;
if (shifKeyDown)
speed = 10; // error - can't assign to a readonly
else
speed = 1; // error
In a similar way you can embed a tertiary expression in other code. As well as making the source code more compact (and in some cases more readable as a result) it can also make the generated machine code more compact and efficient:
MoveCar((shiftKeyDown) ? 10 : 1);
...may generate less code than having to call the same method twice:
if (shiftKeyDown)
MoveCar(10);
else
MoveCar(1);
Of course, it's also a more convenient and concise form (less typing, less repetition, and can reduce the chance of errors if you have to duplicate chunks of code in an if/else). In clean "common pattern" cases like this:
object thing = (reference == null) ? null : reference.Thing;
... it is simply faster to read/parse/understand (once you're used to it) than the long-winded if/else equivalent, so it can help you to 'grok' code faster.
Of course, just because it is useful does not mean it is the best thing to use in every case. I'd advise only using it for short bits of code where the meaning is clear (or made more clear) by using ?: - if you use it in more complex code, or nest ternary operators within each other it can make code horribly difficult to read.

I usually choose a ternary operator when I'd have a lot of duplicate code otherwise.
if (a > 0)
answer = compute(a, b, c, d, e);
else
answer = compute(-a, b, c, d, e);
With a ternary operator, this could be accomplished with the following.
answer = compute(a > 0 ? a : -a, b, c, d, e);

I find it particularly helpful when doing web development if I want to set a variable to a value sent in the request if it is defined or to some default value if it is not.

A really cool usage is:
x = foo ? 1 :
bar ? 2 :
baz ? 3 :
4;

Sometimes it can make the assignment of a bool value easier to read at first glance:
// With
button.IsEnabled = someControl.HasError ? false : true;
// Without
button.IsEnabled = !someControl.HasError;

I'd recommend limiting the use of the ternary(?:) operator to simple single line assignment if/else logic. Something resembling this pattern:
if(<boolCondition>) {
<variable> = <value>;
}
else {
<variable> = <anotherValue>;
}
Could be easily converted to:
<variable> = <boolCondition> ? <value> : <anotherValue>;
I would avoid using the ternary operator in situations that require if/else if/else, nested if/else, or if/else branch logic that results in the evaluation of multiple lines. Applying the ternary operator in these situations would likely result in unreadable, confusing, and unmanageable code. Hope this helps.

The conditional operator is great for short conditions, like this:
varA = boolB ? valC : valD;
I use it occasionally because it takes less time to write something that way... unfortunately, this branching can sometimes be missed by another developer browsing over your code. Plus, code isn't usually that short, so I usually help readability by putting the ? and : on separate lines, like this:
doSomeStuffToSomething(shouldSomethingBeDone()
? getTheThingThatNeedsStuffDone()
: getTheOtherThingThatNeedsStuffDone());
However, the big advantage to using if/else blocks (and why I prefer them) is that it's easier to come in later and add some additional logic to the branch,
if (shouldSomethingBeDone()) {
doSomeStuffToSomething(getTheThingThatNeedsStuffDone());
doSomeAdditionalStuff();
} else {
doSomeStuffToSomething(getTheOtherThingThatNeedsStuffDone());
}
or add another condition:
if (shouldSomethingBeDone()) {
doSomeStuffToSomething(getTheThingThatNeedsStuffDone());
doSomeAdditionalStuff();
} else if (shouldThisOtherThingBeDone()){
doSomeStuffToSomething(getTheOtherThingThatNeedsStuffDone());
}
So, in the end, it's about convenience for you now (shorter to use :?) vs. convenience for you (and others) later. It's a judgment call... but like all other code-formatting issues, the only real rule is to be consistent, and be visually courteous to those who have to maintain (or grade!) your code.
(all code eye-compiled)

One thing to recognize when using the ternary operator that it is an expression not a statement.
In functional languages like scheme the distinction doesn't exists:
(if (> a b) a b)
Conditional ?: Operator
"Doesn't seem to be as flexible as the if/else construct"
In functional languages it is.
When programming in imperative languages I apply the ternary operator in situations where I typically would use expressions (assignment, conditional statements, etc).

While the above answers are valid, and I agree with readability being important, there are 2 further points to consider:
In C#6, you can have expression-bodied methods.
This makes it particularly concise to use the ternary:
string GetDrink(DayOfWeek day)
=> day == DayOfWeek.Friday
? "Beer" : "Tea";
Behaviour differs when it comes to implicit type conversion.
If you have types T1 and T2 that can both be implicitly converted to T, then the below does not work:
T GetT() => true ? new T1() : new T2();
(because the compiler tries to determine the type of the ternary expression, and there is no conversion between T1 and T2.)
On the other hand, the if/else version below does work:
T GetT()
{
if (true) return new T1();
return new T2();
}
because T1 is converted to T and so is T2

If I'm setting a value and I know it will always be one line of code to do so, I typically use the ternary (conditional) operator. If there's a chance my code and logic will change in the future, I use an if/else as it's more clear to other programmers.
Of further interest to you may be the ?? operator.

The advantage of the conditional operator is that it is an operator. In other words, it returns a value. Since if is a statement, it cannot return a value.

There is some performance benefit of using the the ? operator in eg. MS Visual C++, but this is a really a compiler specific thing. The compiler can actually optimize out the conditional branch in some cases.

The scenario I most find myself using it is for defaulting values and especially in returns
return someIndex < maxIndex ? someIndex : maxIndex;
Those are really the only places I find it nice, but for them I do.
Though if you're looking for a boolean this might sometimes look like an appropriate thing to do:
bool hey = whatever < whatever_else ? true : false;
Because it's so easy to read and understand, but that idea should always be tossed for the more obvious:
bool hey = (whatever < whatever_else);

If you need multiple branches on the same condition, use an if:
if (A == 6)
f(1, 2, 3);
else
f(4, 5, 6);
If you need multiple branches with different conditions, then if statement count would snowball, you'll want to use the ternary:
f( (A == 6)? 1: 4, (B == 6)? 2: 5, (C == 6)? 3: 6 );
Also, you can use the ternary operator in initialization.
const int i = (A == 6)? 1 : 4;
Doing that with if is very messy:
int i_temp;
if (A == 6)
i_temp = 1;
else
i_temp = 4;
const int i = i_temp;
You can't put the initialization inside the if/else, because it changes the scope. But references and const variables can only be bound at initialization.

The ternary operator can be included within an rvalue, whereas an if-then-else cannot; on the other hand, an if-then-else can execute loops and other statements, whereas the ternary operator can only execute (possibly void) rvalues.
On a related note, the && and || operators allow some execution patterns which are harder to implement with if-then-else. For example, if one has several functions to call and wishes to execute a piece of code if any of them fail, it can be done nicely using the && operator. Doing it without that operator will either require redundant code, a goto, or an extra flag variable.

With C# 7, you can use the new ref locals feature to simplify the conditional assignment of ref-compatible variables. So now, not only can you do:
int i = 0;
T b = default(T), c = default(T);
// initialization of C#7 'ref-local' variable using a conditional r-value⁽¹⁾
ref T a = ref (i == 0 ? ref b : ref c);
...but also the extremely wonderful:
// assignment of l-value⁽²⁾ conditioned by C#7 'ref-locals'
(i == 0 ? ref b : ref c) = a;
That line of code assigns the value of a to either b or c, depending on the value of i.
Notes
1. r-value is the right-hand side of an assignment, the value that gets assigned.
2. l-value is the left-hand side of an assignment, the variable that receives the assigned value.

Related

Null-coalescing out parameter gives unexpected warning

Using this construct:
var dict = new Dictionary<int, string>();
var result = (dict?.TryGetValue(1, out var value) ?? false) ? value : "Default";
I get an error saying CS0165 use of unassigned local variable 'value' which is not what I expect. How could value possibly be undefined? If the dictionary is null the inner statement will return false which will make the outer statement evaluate to false, returning Default.
What am I missing here? Is it just the compiler being unable to evaluate the statement fully? Or Have I messed it up somehow?
Your analysis is correct. It is not the analysis the compiler makes, because the compiler makes the analysis that is required by the C# specification. That analysis is as follows:
If the condition of a condition?consequence:alternative expression is a compile-time constant true then the alternative branch is not reachable; if false, then the consequence branch is not reachable; otherwise, both branches are reachable.
The condition in this case is not a constant, therefore the consequence and alternative are both reachable.
local variable value is only definitely assigned if dict is not null, and therefore value is not definitely assigned when the consequence is reached.
But the consequence requires that value be definitely assigned
So that's an error.
The compiler is not as smart as you, but it is an accurate implementation of the C# specification. (Note that I have not sketched out here the additional special rules for this situation, which include predicates like "definitely assigned after a true expression" and so on. See the C# spec for details.)
Incidentally, the C# 2.0 compiler was too smart. For example, if you had a condition like 0 * x == 0 for some int local x it would deduce "that condition is always true no matter what the value of x is" and mark the alternative branch as unreachable. That analysis was correct in the sense that it matched the real world, but it was incorrect in the sense that the C# specification clearly says that the deduction is only to be made for compile-time constants, and equally clearly says that expressions involving variables are not constant.
Remember, the purpose of this thing is to find bugs, and what is more likely? Someone wrote 0 * x == 0 ? foo : bar intending that it have the meaning "always foo", or that they've written a bug by accident? I fixed the bug in the compiler and since then it has strictly matched the specification.
In your case there is no bug, but the code is too complicated for the compiler to analyze, so it is probably also too complicated to expect humans to analyze. See if you can simplify it. What I might do is:
public static V GetValueOrDefault<K, V>(
this Dictionary<K, V> d,
K key,
V defaultValue)
{
if (d != null && d.TryGetValue(key, out var value))
return value;
return defaultValue;
}
…
var result = dict.GetValueOrDefault(1, "Default");
The goal should be to make the call site readable; I think my call site is considerably more readable than yours.
Is it just the compiler being unable to evaluate the statement fully?
Yes, more or less.
The compiler does not track unassigned, it tracks the opposite 'defintely assigned'. It has to stop somewhere, in this case it would need to incorporate knowledge about the library method TryGetValue(). It doesn't.

Non-shortcircuting boolean operators and C# 7 Pattern matching

Im currently writing an C# application, targeting .NET 4.7 (C# 7). I am confused after I tried using the new way of declaring a variable utilizing the "is" keyword:
if (variable is MyClass classInstance)
This way it works, but when doing:
if (true & variable is MyClass classInstance)
{
var a = classInstance;
}
Visual Studio (I'm using 2017) shows me the the Error Use of unassigned local variable 'classInstance'. Using the short-circuting version of & (&&) it works fine. Am I missing something about the & operator? (I know using the shortcircuting versions are much more commonly used, but at this point I'm just curious)
This one hurt my head, but I think I have got it figured out.
This confusion is caused by two quirks: the way the is operation leaves the variable undeclared (not null), and the way the compiler optimizes away Boolean, but not bitwise, operations.
Quirk 1. If the cast fails, the variable is unassigned (not null)
Per the documentation for the new is syntax:
If exp is true and is is used with an if statement, varname is assigned and has local scope within the if statement only.
If you read between the lines, this means that if the is cast fails, the variable is considered unassigned. This may be counterintuitive (some might expect it to be null instead). This means that any code within the if block that relies on the variable will not compile if there is any chance the overall if clause could evaluate to true without a type match present. So for example
This compiles:
if (instance is MyClass y)
{
var x = y;
}
And this compiles:
if (true && instance is MyClass y)
{
var x = y;
}
But this does not:
void Test(bool f)
{
if (f && instance is MyClass y)
{
var x = y; //Error: Use of unassigned local variable
}
}
Quirk 2. Boolean operations are optimized away, binary ones are not
When the compiler detects a predestined Boolean result, the compiler will not emit unreachable code, and skips certain validations as a result. For example:
This compiles:
void Test(bool f)
{
object neverAssigned;
if (false && f)
{
var x = neverAssigned; //OK (never executes)
}
}
But if you use & instead of &&, it does not compile:
void Test(bool f)
{
object neverAssigned;
if (false & f)
{
var x = neverAssigned; //Error: Use of unassigned local variable
}
}
When the compiler sees something like true && it just ignores it completely. Thus
if (true && instance is MyClass y)
Is exactly the same as
if (instance is MyClass y)
But this
if (true & instance is MyClass y)
Is NOT the same. The compiler still needs to emit code that performs the & operation and uses its output in a conditional statement. Or even if it doesn't, the current C# 7 compiler apparently performs the same validations as if it were. This may seem a little strange, but bear in mind that when you use & instead of &&, there is a guarantee that the & must execute, and though it seems unimportant in this example, the general case must allow for additional complexifying factors, such as operator overloading.
How the quirks combine
In the last example, the result of the if clause is determined at run time, not compile time. So the compiler can't be certain that y will end up being assigned before the contents of the if block are executed. Thus you get
if (true & instance is MyClass y)
{
var x = y; //Error: use of unassigned local variable
}
TLDR
In the situation of a compound logical operation, c# can't be sure that the overall if condition will resolve to true if and only if the cast is successful. Absent that certainty, it can't allow access to the variable, since it might be unassigned. An exception is made when the expression can be reduced to non-compound operation at compile time, for example by removing true &&.
Workaround
I think the way we are meant to use the new is syntax is as a single condition with an if clause. Adding true && at the beginning works because the compiler simply removes it. But anything else combined with the new syntax creates ambiguity about whether the new variable will be in an unassigned state when the code block runs, and the compiler can't allow that.
The workaround of course is to nest your conditions instead of combining them:
Won't work:
void Test(bool f)
{
if (f & instance is MyClass y)
{
var x = y; //Error: Use of unassigned local variable
}
}
Works fine:
void Test(bool f)
{
if (f)
{
if (instance is MyClass y)
{
var x = y; //Works
}
}
}
This is due to the rules on definite assignment, which have a special case for &&, but don't have a special case for &. I believe it's working as intended by the C# design team, but that the specification may have a little bit more work to do, at least in terms of clarity.
From the ECMA C# 5 standard, section 5.3.3.24:
For an expression expr of the form expr-first && expr-second:
...
The definite assignment state of v after expr is determined by:
If expr-first is a constant expression with the value false, then the definite assignment state of v after expr is the same as the definite assignment state of v after expr-first.
Otherwise, if the state of v after expr-first is definitely assigned, then the state of v after expr is definitely assigned.
Otherwise, if the state of v after expr-second is definitely assigned, and the state of v after expr-first is “definitely assigned after false expression”, then the state of v after expr is definitely assigned.
Otherwise, if the state of v after expr-second is definitely assigned or “definitely assigned after true expression”, then the state of v after expr is “definitely assigned after true expression”.
...
The relevant part for this case is the one I've highlighted in bold. classInstance is "definitely assigned after true expression" with the pattern (expr-second above), and none of the earlier cases apply, so the overall state at the end of the condition is "definitely assigned after true expression". That means within the if statement body, it's definitely assigned.
There's no equivalent clause for the & operator. While there potentially could be, it would be complicated by the types involved - it would have to only apply to the & operator when used with bool expressions, and I don't think most of the rest of definite assignment deals with types in that way.
Note that you don't need to use pattern matching to see this.
Consider the following program:
using System;
class Program
{
static void Main()
{
bool a = false;
bool x;
bool y = true;
if (true & (y && (x = a)))
{
Console.WriteLine(x);
}
}
}
The expression y && (x = a) is another one where x ends up being "definitely assigned after true expression". Again, the code above fails to compile due to x not being definitely assigned, whereas if you change the & to && it compiles. So at least this isn't an issue in pattern matching itself.
What confuses me somewhat is why x isn't still "definitely assigned after true expression" due to 5.3.3.21 ("5.3.3.21 General rules for expressions with embedded expressions"), which contains:
The definite assignment state of v at the end of expr is the same as the definite assignment state at the end of exprn.
I suspect this is meant to only include "definitely assigned" or "not definitely assigned", rather than including the "definitely assigned after true expression" part - although it's not as clear as it should be.
Am I missing something about the & operator?
No, I don't think so. Your expectations seem correct to me. Consider this alternative example, which does compile without error:
object variable = null;
MyClass classInstance;
if (true & ((classInstance = variable as MyClass) != null))
{
var a = classInstance;
}
var b = classInstance;
(To me, it's more interesting to consider the assignment outside the if body, since that's where the short-circuiting would affect behavior.)
With the explicit assignment, the compiler recognizes classInstance as definitely assigned, in the assignments of both a and b. It should be able to do the same thing with the new syntax.
With logical and, short-circuiting or not shouldn't matter. Your first value is true, so the second half should always need to be evaluated to get the whole expression. As you've noted, the compiler does treat the & and && differently though, which is unexpected.
A variation on this is this code:
static void M3()
{
object variable = null;
if (true | variable is MyClass classInstance)
{
var a = classInstance;
}
}
The compiler correctly identifies classInstance as not definitely assigned when || is used, but has the same apparent misbehavior with | (i.e. also saying that classInstance is not definitely assigned), even though with the non-short-circuiting operator, the assignment must happen regardless.
Again, the above works correctly with the assignment is explicit, rather than using the new syntax.
If this were just about the definite assignment rules not being addressed with the new syntax, then I would expect && to be as broken as &. But it's not. The compiler handles that correctly. And indeed, in the feature documentation (I hesitate to say "specification", because there's no ECMA-ratified C# 7 specification yet), it reads:
The type_pattern both tests that an expression is of a given type and casts it to that type if the test succeeds. This introduces a local variable of the given type named by the given identifier. That local variable is definitely assigned when the result of the pattern-matching operation is true. [emphasis mine]
Since short-circuiting produces correct behavior without pattern matching, and since pattern matching produces correct behavior without short-circuiting (and definite-assignment is explicitly addressed in the feature description), I would say this is straight-up a compiler bug. There's probably some overlooked interaction between non-short-circuiting Boolean operators and the way the pattern-matched expression is evaluated that causes the definite assignment to get lost in the shuffle.
You should consider reporting it to the authorities. I think these days, the Roslyn GitHub issue-tracking is where they track this sort of thing. It might help if you explain in your report how you found this and why that particular syntax is important in your scenario (since in the code you posted, the && operator works equivalently…the non-short-circuiting & doesn't seem to confer any advantage to the code).

C#: Order of execution of operands in an IF statement

I came across some statements while surfing the .net source:
If( null != name)
If( false == check())
what is the difference between (name != null) and (Check() == false) statements from the above statements?
Can any one get me clear of this? Please.
I'm sure this is a duplicate, but I can't find it right now.
Code with the constant first is usually written by developers with an (old) background in C, where you might write this:
if (NULL == x)
instead of this:
if (x == NULL)
just in case you made a typo like this:
if (x = NULL) // Valid, but doesn't do what you want.
In most cases in C#, you don't need to do this - because the condition in an if statement has to be convertible to bool.
It would make a difference when you're comparing to a Boolean constant:
if ((Check() = false) // Eek!
... which is one reason to just write:
if (!Check())
Basically, putting the variable first is generally more readable - and in C# the reason for putting the constant first is almost never applicable anyway. (Modern C and C++ compilers will usually give you a warning anyway, so it's no longer a great idea in those languages either, as far as I'm aware...)
In terms of the order of evaluation, there is a theoretical difference in that the left-hand operand will be evaluated before the right-hand operand... but as the constants null and false don't have any side-effects, there's no real difference.
I think this style comes with C/C++ background, where the operator = which can also be used inside if statement, which could be used for comparison as well as assignment.
The statement
if( null != name) is same as if(name != null), so as the other statement
To safeguard from mistakenly assigning the value to the left hand side, this style of check is used in C/C++,
Take a look Coding Horror Yoda Conditions
Using if(constant == variable) instead of if(variable == constant),
like if(4 == foo). Because it's like saying "if blue is the sky" or
"if tall is the man".
The odd reversal looks like it was written by a C/C++ programmer... basically, in C/C++, if you accidentally type:
if(name = null)
instead of
if(name == null)
then that compiles and changes the value to null when invoked. A C/C++ habit to avoid this mistake is to use a constant such as null / false always on the left. This is because you can't reassign a constant, so it generates a compiler error if you use = instead of ==. In C# it (if(a = null)) doesn't usually compile, so that is not a concern.
There is no difference re the position here - both sides are evaluated. Idiomatic C# for this would be simply:
if(name != null) ...
if(!check()) ...

Doubts about the 'var' keyword and ternary operator ?:

If var keyword is resolved at compile time, how does the following work?
class A {
}
class B : A {
}
int k = 1;
var x = (k < 0) ? new B() : new A();
Edit:
I finally understood that the problem is not about the var itself, but about the behaviour of the ?: operator. For some reason, I thought that the following could be possible:
object x = something ? 1 : ""
and that's not possible at all :)
Related question (about ternary operator):
Why assigning null in ternary operator fails: no implicit conversion between null and int?
The result is of type A, because both of the variables are of type A, and at least one of them is directly of type A (not through some conversion).
The compiler takes a look at both parts of the ternary expression, and if one of them is a subtype of the other, the entire expression becomes the more general supertype.
However, if neither is directly of the common type, then a compiler error occurs, probably because it doesn't know how much to upcast for you (and it doesn't feel like finding out).
See here:
The conditional operator (?:) returns one of two values depending on the value of a Boolean expression. Following is the syntax for the conditional operator.
condition ? first_expression : second_expression;
[...]
Either the type of first_expression and second_expression must be the same, or an implicit conversion must exist from one type to the other.
The result is A. An easy way to confirm it is to place your mouse over the var.
I haven't tested this degenerate case. But I would bet either (1) compiler complains or (2) 'x' is of type 'A'.

Why does one often see "null != variable" instead of "variable != null" in C#?

In c#, is there any difference in the excecution speed for the order in which you state the condition?
if (null != variable) ...
if (variable != null) ...
Since recently, I saw the first one quite often, and it caught my attention since I was used to the second one.
If there is no difference, what is the advantage of the first one?
It's a hold-over from C. In C, if you either use a bad compiler or don't have warnings turned up high enough, this will compile with no warning whatsoever (and is indeed legal code):
// Probably wrong
if (x = 5)
when you actually probably meant
if (x == 5)
You can work around this in C by doing:
if (5 == x)
A typo here will result in invalid code.
Now, in C# this is all piffle. Unless you're comparing two Boolean values (which is rare, IME) you can write the more readable code, as an "if" statement requires a Boolean expression to start with, and the type of "x=5" is Int32, not Boolean.
I suggest that if you see this in your colleagues' code, you educate them in the ways of modern languages, and suggest they write the more natural form in future.
There is a good reason to use null first: if(null == myDuck)
If your class Duck overrides the == operator, then if(myDuck == null) can go into an infinite loop.
Using null first uses a default equality comparator and actually does what you were intending.
(I hear you get used to reading code written that way eventually - I just haven't experienced that transformation yet).
Here is an example:
public class myDuck
{
public int quacks;
static override bool operator ==(myDuck a, myDuck b)
{
// these will overflow the stack - because the a==null reenters this function from the top again
if (a == null && b == null)
return true;
if (a == null || b == null)
return false;
// these wont loop
if (null == a && null == b)
return true;
if (null == a || null == b)
return false;
return a.quacks == b.quacks; // this goes to the integer comparison
}
}
Like everybody already noted it comes more or less from the C language where you could get false code if you accidentally forget the second equals sign. But there is another reason that also matches C#: Readability.
Just take this simple example:
if(someVariableThatShouldBeChecked != null
&& anotherOne != null
&& justAnotherCheckThatIsNeededForTestingNullity != null
&& allTheseChecksAreReallyBoring != null
&& thereSeemsToBeADesignFlawIfSoManyChecksAreNeeded != null)
{
// ToDo: Everything is checked, do something...
}
If you would simply swap all the null words to the beginning you can much easier spot all the checks:
if(null != someVariableThatShouldBeChecked
&& null != anotherOne
&& null != justAnotherCheckThatIsNeededForTestingNullity
&& null != allTheseChecksAreReallyBoring
&& null != thereSeemsToBeADesignFlawIfSoManyChecksAreNeeded)
{
// ToDo: Everything is checked, do something...
}
So this example is maybe a bad example (refer to coding guidelines) but just think about you quick scroll over a complete code file. By simply seeing the pattern
if(null ...
you immediately know what's coming next.
If it would be the other way around, you always have to scan to the end of the line to see the nullity check, just letting you stumble for a second to find out what kind of check is made there. So maybe syntax highlighting may help you, but you are always slower when those keywords are at the end of the line instead of the front.
I guess this is a C programmer that has switched languages.
In C, you can write the following:
int i = 0;
if (i = 1)
{
...
}
Notice the use of a single equal sign there, which means the code will assign 1 to the variable i, then return 1 (an assignment is an expression), and use 1 in the if-statement, which will be handled as true. In other words, the above is a bug.
In C# however, this is not possible. There is indeed no difference between the two.
In earlier times, people would forget the '!' (or the extra '=' for equality, which is more difficult to spot) and do an assignment instead of a comparison. putting the null in front eliminates the possibility for the bug, since null is not an l-value (I.E. it can't be assigned to).
Most modern compilers give a warning when you do an assignment in a conditional nowadays, and C# actually gives an error. Most people just stick with the var == null scheme since it's easier to read for some people.
I don't see any advantage in following this convention. In C, where boolean types don't exist, it's useful to write
if( 5 == variable)
rather than
if (variable == 5)
because if you forget one of the eaqual sign, you end up with
if (variable = 5)
which assigns 5 to variable and always evaluate to true. But in Java, a boolean is a boolean. And with !=, there is no reason at all.
One good advice, though, is to write
if (CONSTANT.equals(myString))
rather than
if (myString.equals(CONSTANT))
because it helps avoiding NullPointerExceptions.
My advice would be to ask for a justification of the rule. If there's none, why follow it? It doesn't help readability
To me it's always been which style you prefer
#Shy - Then again if you confuse the operators then you should want to get a compilation error or you will be running code with a bug - a bug that come back and bite you later down the road since it produced unexpected behaviour
As many pointed out, it is mostly in old C code it was used to identify compilation error, as compiler accepted it as legal
New programming language like java, go are smart enough to capture such compilation errors
One should not use "null != variable" like conditions in code as it very unreadable
One more thing... If you are comparing a variable to a constant (integer or string for ex.), putting the constant on the left is good practice because you'll never run into NullPointerExceptions :
int i;
if(i==1){ // Exception raised: i is not initialized. (C/C++)
doThis();
}
whereas
int i;
if(1==i){ // OK, but the condition is not met.
doThis();
}
Now, since by default C# instanciates all variables, you shouldn't have that problem in that language.

Categories

Resources