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).&
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.&&
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.