I'm going to be unpopular and say Yes, it is bad practice. IF the functionality of your code is relying on it to implement conditional logic.
ie
if(quickLogicA && slowLogicB) {doSomething();}
is good, but
if(logicA && doSomething()) {andAlsoDoSomethingElse();}
is bad, and surely no-one would agree with?!
if(doSomething() || somethingElseIfItFailed() && anotherThingIfEitherWorked() & andAlwaysThisThing())
{/* do nothing */}
Reasoning :
Your code errors if both sides are evaluated rather than simply not performing the logic. It has been argued that this is not a problem, the 'and' operator is defined in c# so the meaning is clear. However, I contend that this is not true.
Reason 1. Historical
Essentially you are relying on (what was originally intended as) a compiler optimization to provide functionality in your code.
Although in c# the language specification guarantees the boolean 'and' operator does short circuiting. This is not true of all languages and compilers.
wikipeda lists various languages and their take on short circuiting http://en.wikipedia.org/wiki/Short-circuit_evaluation as you can there are many approaches. And a couple of extra problems I don't go into here.
In particular, FORTRAN, Pascal and Delphi have compiler flags which toggle this behavior.
Therefore : You may find you code works when compiled for release, but not for debug or with an alternate compiler etc.
Reason 2. Language differences
As you can see from wikipedia, not all languages take the same approach to short circuiting, even when they specify how the boolean operators should handle it.
In particular VB.Net's 'and' operator does not short circuit and TSQL has some peculiarities.
Given that a modern 'solution' is likely to include a number of languages, such as javascript, regex, xpath etc you should take this into account when making your code functionality clear.
Reason 3. Differences within a language
For example VB's inline if behaves differently from its if. Again in modern applications your code may move between, for example code behind and an inline webform, you have to be aware of the differences in meaning.
Reason 4. Your specific example of null checking the parameter of a function
This is a very good example. In that it is something everyone does, but is actually bad practice when you think about it.
Its a very common to see this kind of check as it reduces your lines of code considerably. I doubt anyone would bring it up in a code review. (and obviously from the comments and rating you can see it's popular!)
However, it fails best practice for more than one reason!
Its very clear from numerous sources, that best practice is to check your parameters for validity before you use them and to throw an exception if they are invalid. Your code snippet dosn't show the surrounding code, but you should probably be doing something like:
if (smartphone == null)
{
//throw an exception
}
// perform functionality
You are calling a function from within the conditional statement. Although your function's name implies that it simply calculates a value, it can hide side effects. eg
Smartphone.GetSignal() { this.signal++; return this.signal; }
else if (smartphone.GetSignal() < 1)
{
// Do stuff
}
else if (smartphone.GetSignal() < 2)
{
// Do stuff
}
best practice would suggest:
var s = smartphone.GetSignal();
if(s < 50)
{
//do something
}
If you apply these best practices to your code you can see that your opportunity to achieve shorter code through the use of the hidden conditional disappears. Best practice is to do something, to handle the case where smartphone is null.
I think you will find that this is also the case for other common usages. You have to remember we also have :
inline conditionals
var s = smartphone!=null ? smartphone.GetSignal() : 0;
and null coalescence
var s = smartphoneConnectionStatus ?? "No Connection";
which provide similar short code length functionality with more clarity
numerous links to support all my points:
https://stackoverflow.com/questions/1158614/what-is-the-best-practice-in-case-one-argument-is-null
Constructor parameter validation in C# - Best practices
Should one check for null if he does not expect null?
https://msdn.microsoft.com/en-us/library/seyhszts%28v=vs.110%29.aspx
https://stackoverflow.com/questions/1445867/why-would-a-language-not-use-short-circuit-evaluation
http://orcharddojo.net/orchard-resources/Library/DevelopmentGuidelines/BestPractices/CSharp
examples of compiler flags that affect short circuiting:
Fortran : "sce | nosce By default, the compiler performs short circuit evaluation in selected logical expressions using XL Fortran rules. Specifying sce allows the compiler to use non-XL Fortran rules. The compiler will perform short circuit evaluation if the current rules allow it. The default is nosce."
Pascal : "B - A flag directive that controls short-circuit evaluation. See Order of evaluation of operands of dyadic operators for more information about short-circuit evaluation. See also the -sc compiler option for the command-line compiler for more information (documented in the User's Manual)."
Delphi : "Delphi supports short circuit evaluation by default. It can be turned off using the {$BOOLEVAL OFF} compiler directive."
||
short-circuits, the operator|
(single pipe) does not (&&
and&
behave the same). As the short-circuit operators are used much more frequently, I recommend to mark usages of the non-short-circuit ones with a comment to explain why you need their behavior (mostly things like method invocations that all need to happen). – linac May 20 '15 at 12:58&
or|
to make sure a side-effect happens is something I'd say certainly is bad practice: It won't cost you anything to put that method call on its own line. – Jon Hanna May 20 '15 at 14:01if(foo != null && (foo.TryOneThing() | foo.TryAnotherThing())) {…}
is certainly a case for many more lines and some explicit variables. – linac May 20 '15 at 14:13&&
s would make it a bit nicer, but doing that same thing in a chain of 3 nestedif
s would be a lot messier. – Michael Shaw May 20 '15 at 15:56AndAlso
andOrElse
. I don't believe it was as widely known before LINQ, and perhaps even LINQ users may not be as aware of what it does as they should be. – ps2goat May 20 '15 at 18:53&&
is short-circuit and&
is not, but they're very different operators.&&
is a logical "and";&
is a bitwise "and". It's possible forx && y
to be true whilex & y
is false. – Keith Thompson May 20 '15 at 19:40|
is both, a non-short-circuit logical operator and a binary operator - depending on its arguments. Interesting question whether it's more complex in C/C++ where "bitwise values" like int can be interpreted as logical values, or in C#, where the two are completely distinct, but it still use an operator that looks the same … – linac May 20 '15 at 21:51if
statements suddenly started evaluatingelse
clauses even when the conditions are true. – Kaz May 21 '15 at 20:51or
operators in languages that implement short-circuit evaluation. It works differently betweenand
andor
, though:and
evaluates the second operand only if the first operand expression results in true, whileor
evaluates the second operand only if the first expression results in false. ie in both cases, the least number of operand expressions are evaluated as necessary to determine the overall operator result. – Sepster Jun 14 '16 at 12:59