Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
Are there any understanding / maintainability issues that result from code like
inVar1 == 0 ? NULL : v.push_back(inVar1);
inVar2 == 0 ? NULL : v.push_back(inVar2);
and so forth.
The possibly confusing idea is using the ternary operator for program flow rather than variable assignment, which is the usual explanation.
I haven't seen coding standards at work that address this usage, so while I'm comfortable doing this I'd like to find out if there is a good reason not to.
I think it's confusing and a lot harder to read than simply typing;
if (inVar != 0)
v.push_back(inVar);
I had to scan your example several times to figure out what the result would be with any certainty. I'd even prefer a single-line if() {} statement than your example - and I hate single-line if statements :)
The ternary operator is meant to return a value.
IMO, it should not mutate state, and the return value should be used.
In the other case, use if statements. If statements are meant to execute code blocs.
The ternary is a good thing, and I generally promote it's usage.
What you're doing here however tarnishes it's credibility. It's shorter, yes, but it's needlessly complicated.
I think this should be avoided. You could use a 1-line if statement in its place.
if(inVar1 != 0) v.push_back(inVar1);
Compilers these days will make an if as fast as a ternary operator.
You goal should be how easy is it for another software developer to read.
I vote for
if ( inVar != 0 )
{
v.push_back( inVar );
}
why the brackets...because one day you may want to put something else in there and the brackets are pre-done for you. Most editors these days will put them in anyway.
Your use of the ternary operator gains you nothing and you hurt the codes readability.
Since the ternary operator returns a value that you are not using it is odd code. The use of an if is much more clear in a case like yours.
As litb mentioned in the comments, this isn't valid C++. GCC, for example, will emit an error on this code:
error: `(&v)->std::vector<_Tp, _Alloc>::push_back [with _Tp = int, _Alloc =
std::allocator<int>](((const int&)((const int*)(&inVar1))))' has type `void'
and is not a throw-expression
However, that can be worked around by casting:
inVar1 == 0 ? (void)0 : v.push_back(inVar1);
inVar2 == 0 ? (void)0 : v.push_back(inVar2);
But at what cost? And for what purpose?
It's not like using the ternary operator here is any more concise than an if-statement in this situation:
inVar1 == 0 ? NULL : v.push_back(inVar1);
if(inVar1 != 0) v.push_back(inVar1);
While, in practice, I agree with the sentiments of those who discourage this type of writing (when reading, you have to do extra work to scan the expression for its side effects), I'd like to offer
!inVar1 ?: v.push_back(inVar1);
!inVar2 ?: v.push_back(inVar2);
...if you're going for obscure, that is. GCC allows x ?: y in place of x ? x : y. :-)
I use ternary operator when I need to call some function with conditional arguments - in this case it is better then if.
Compare:
printf("%s while executing SQL: %s",
is_sql_err() ? "Error" : "Warning", sql_msg());
with
if (is_sql_err())
printf("Error while executing SQL: %s", sql_msg());
else
printf("Warning while executing SQL: %s", sql_msg());
I find the former is more appealing. And it complies to DRY principle, unlike latter - you don't need to write two nearly identical lines.
I think you would be better served in doing a proper if structure. I even prefer to always have braces with my if structures, in the event I have to add lines later to the conditional execution.
if (inVar != 0) {
v.push_back(inVar);
}
I think that sometimes the ternary are a necessary evil in initializer lists for constructors. I use them mostly for constructors where I want to allocate memory and set some pointer to point at it before the body of the constructor.
An example, suppose you had an integer storage class that you wanted to have take a vector as an input but the internal representation is an array:
class foo
{
public:
foo(std::vector<int> input);
private:
int* array;
unsigned int size;
};
foo:foo(std::vector<int> input):size(input.size()), array( (input.size()==0)?
NULL : new int[input.size])
{
//code to copy elements and do other start up goes here
}
This is how I use the ternary operator. I don't think it is as confusing as some people do but I do think that one should limit how much they use it.
Most of the tortured ternaries (how's that for alliteration?) I see are merely attempts at putting logic that really belongs in an if statement in a place where an if statement doesn't belong or can't go.
For instance:
if (inVar1 != 0)
v.push_back(inVar1);
if (inVar2 != 0)
v.push_back(inVar2);
works assuming that v.push_back is void, but what if it's returning a value that needs to get passed to another function? In that case, it would have to look something like this:
SomeType st;
if (inVar1 != 0)
st = v.push_back(inVar1);
else if (inVar2 != 0)
st = v.push_back(inVar2);
SomeFunc(st);
But that's more to digest for such a simple piece of code. My solution: define another function.
SomeType GetST(V v, int inVar1, int inVar2){
if (inVar1 != 0)
return v.push_back(inVar1);
if (inVar2 != 0)
return v.push_back(inVar2);
}
//elsewhere
SomeFunc(GetST(V v, inVar1, inVar2));
At any rate, the point is this: if you have some logic that's too tortured for a ternary but will clutter up your code if it's put in an if statement, put it somewhere else!
inVar1 != 0 || v.push_back(inVar1);
inVar2 != 0 || v.push_back(inVar2);
common pattern found in languages like Perl.
If you have multiple method invocations in one or both of the tenary arguments then its wrong. All lines of code regardless of what statement should be short and simple, ideally not compounded.
A proper if statement is more readable, as others have mentioned. Also, when you're stepping through your code with a debugger, you won't be able to readily see which branch of an if is taken when everything is in one line or you're using a ternary expression:
if (cond) doIt();
cond ? noop() : doIt();
Whereas the following is much nicer to step through (whether you have the braces or not):
if (cond) {
doIt();
}
As mentioned, it's not shorter or clearer than a 1 line if statement. However, it's also no longer - and isn't really that hard to grok. If you know the ternary operator, it's pretty obvious what's happening.
After all, I don't think anyone would have a problem if it was being assigned to a variable (even if it was mutating state as well):
var2 = inVar1 == 0 ? NULL : v.push_back(inVar1);
The fact that the ternary operator always returns a value - IMO - is irrelevant. There's certainly no requirement that you use all return values...after all, an assignment returns a value.
That being said, I'd replace it with an if statement if I ran across it with a NULL branch.
But, if it replaced a 3 line if statement:
if (inVar == 0) {
v.doThingOne(1);
} else {
v.doThingTwo(2);
}
with:
invar1 == 0 ? v.doThingOne(1) : v.doThingTwo(2);
I might leave it...depending on my mood. ;)
Related
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I often find reason to compare two values or objects in C# - often different types - and I find myself unhappy with the code I write.
The code ends up looking (to me) verbose and unclear and I frequently end up feeling the need to add a comment that says "//check if they're equal".
(I often blame the fact that that there's no nullsafe-dereference operator like I saw in Groovy once.)
In a recent example, I have two variables:
string s;
int? i;
Let's say I want to compare them so that I can do something if they're "obviously equal".
I'm defining them as "obviously equal" if either:
a) the int? doesn't contain a number and the string is null, or else...
b) the string is what you'd get if you wrote out the numerical value of the int? in a plain / unformatted fashion.
[Note that in this case I'm not actually bothered whether the number 1234 is considered equal to the strings "01234" or "1234.00" (or indeed "1234,00", if you're what I consider foreign).
You can have flexibility either way on those as long as "1234" is considered equal, and (e.g.) "1233+1" and "1234z" aren't.
You can also have flexibility on whether an int? that doesn't contain a number is considered equal to an empty string.]
So, I want some [clear / simple / short - with apologies for the subjectiveness] expression to put in my "if" condition which will perform the check as required above and definitely won't throw an exception.
What are my options?
(If anyone wants to compare their solution to how this might be more easily expressed in other languages, feel free. It's always useful to know where the greener grass is...)
UPDATE:
My own code boils down to something like...
if (s == (i.HasValue ? i.Value.ToString() : null))
which actually doesn't look so bad now that s and i aren't meaningfully named properties on other objects.
[However, I don't really like leaving an "==" comparison in there because (though it works for strings because of string-interning and/or an operator override or something) it's normally checking reference equality, right? So I'd consider replacing that with string.Equals... but that's even more horrible to read.]
When you also have to check the parent objects (on which the "meaningful properties" exist) for null, the code just gets so long-winded - and that's what was on my mind when I posted the question, I think.
I wanted to see whether everybody else had something I was missing.
I really want to be able to simply check for the positive condition and have everything else evaluate to false (without throwing a visible exception). So...
if ( (someObject.s == null && someOther.i == null)
||
(int.Parse(someObject.s) == someOther.i) )
or similar would be very "happy" if all possible (null-ref / parse) exceptions could be silently coerced to false.
I guess I'm just getting too lazy in my old age....
public static bool ObviouslyEquals<T>(this string s, T? t) where T: struct
{
if (s == null && !t.HasValue)
return true;
if (s == null || !t.HasValue)
return false;
return s.Equals(t.Value.ToString());
}
string s;
int? i;
if (s.ObviouslyEquals(i))...
If there is a value "i" can never be (let's say -1), you could use something like this:
((object)i ?? -1).ToString() == s
This won't work with special number format, though.
So maybe this would help:
int x;
!((i == null) != (s == null) || i != null && (!ToInt32.TryParse(s, out x) || i != x))
Both these methods work, however which is better method to use out of the following:
PlaceHolder PH = ctl.PlaceHoldNu == 1 ? (PlaceHolder)Page.Master.FindControl("PlaceHolder1") : (PlaceHolder)FindControl("PlaceHolder" + ctl.PlaceHoldNu);
Or
PlaceHolder PH;
if (ctl.PlaceHoldNu == 1)
PH = (PlaceHolder)Page.Master.FindControl("PlaceHolder1");
else
PH = (PlaceHolder)FindControl("PlaceHolder" + ctl.PlaceHoldNu);
Another solution would be:
PlaceHolder PH = ctl.PlaceHoldNu == 1
? (PlaceHolder)Page.Master.FindControl("PlaceHolder1")
: (PlaceHolder)FindControl("PlaceHolder" + ctl.PlaceHoldNu);
This solutions uses a minimum of lines but maintains readability.
It's a matter of taste. However, if they get too long, I would prefer the second. But before that happens, I think this looks nice:
PlaceHolder PH =
ctl.PlaceHoldNu == 1
? (PlaceHolder)Page.Master.FindControl("PlaceHolder1")
: (PlaceHolder)FindControl("PlaceHolder" + ctl.PlaceHoldNu);
The best one is the one you prefer using.
They will compile down to the same thing, so it depends on the context. Which one makes the intent of what you are trying to do more clear?
For this case I like the first one, as I feel it's more readable and concise.
A bit more complex than this, and your second approach will be the preferred one.
But this is just as much your own taste than correct
I generally only use the conditional operator on assignments (like you have done), but only when they're simple and easy to read.
The length of you assignments would make me favour the second for readability.
Basically whichever is easiest to parse if you imagine you've never looked at the code before.
Situation: condition check in C++ or C# with many criteria:
if (condition1 && condition2 && condition3)
{
// Do something
}
I've always believed the sequence in which these checks are performed is not guaranteed. So it is not necessarily first condition1 then condition2 and only then condition3. I learned it in my times with C++. I think I was told that or read it somewhere.
Up until know I've always written secure code to account for possible null pointers in the following situation:
if ((object != null) && (object.SomeFunc() != value))
{
// A bad way of checking (or so I thought)
}
So I was writing:
if (object != null)
{
if (object.SomeFunc() != value)
{
// A much better and safer way
}
}
Because I was not sure the not-null check will run first and only then the instance method will be called to perform the second check.
Now our greatest community minds are telling me the sequence in which these checks are performed is guaranteed to run in the left-to-right order.
I'm very surprised. Is it really so for both C++ and C# languages?
Has anybody else heard the version I heard before now?
Short Answer is left to right with short-circuit evaluation. The order is predictable.
// perfectly legal and quite a standard way to express in C++/C#
if( x != null && x.Count > 0 ) ...
Some languages evaluate everything in the condition before branching (VB6 for example).
// will fail in VB6 if x is Nothing.
If x Is Not Nothing And x.Count > 0 Then ...
Ref: MSDN C# Operators and their order or precedence.
They are defined to be evaluated from left-to-right, and to stop evaluating when one of them evaluates to false. That's true in both C++ and C#.
I don't think there is or has been any other way. That would be like the compiler deciding to run statements out of order for no reason. :) Now, some languages (like VB.NET) have different logical operators for short-circuiting and not short-circuiting. But, the order is always well defined at compile time.
Here is the operator precedence from the C# language spec. From the spec ...
Except for the assignment operators,
all binary operators are
left-associative, meaning that
operations are performed from left to
right. For example, x + y + z is
evaluated as (x + y) + z.
They have to be performed from left to right. This allows short circuit evaluation to work.
See the Wikipedia article for more information.
I have seen something like the following a couple times... and I hate it. Is this basically 'cheating' the language? Or.. would you consider this to be 'ok' because the IsNullOrEmpty is evaluated first, all the time?
(We could argue whether or not a string should be NULL when it comes out of a function, but that isn't really the question.)
string someString;
someString = MagicFunction();
if (!string.IsNullOrEmpty(someString) && someString.Length > 3)
{
// normal string, do whatever
}
else
{
// On a NULL string, it drops to here, because first evaluation of IsNullOrEmpty fails
// However, the Length function, if used by itself, would throw an exception.
}
EDIT:
Thanks again to everyone for reminding me of this language fundamental. While I knew "why" it worked, I can't believe I didn't know/remember the name of the concept.
(In case anyone wants any background.. I came upon this while troubleshooting exceptions generated by NULL strings and .Length > x exceptions... in different places of the code. So when I saw the above code, in addition to everything else, my frustration took over from there.)
You're taking advantage of a language feature known as short circuiting. This is not cheating the language but in fact using a feature exactly how it was designed to be used.
If you are asking if its ok to depend on the "short circuit" relational operators && and ||, then yes thats totally fine.
There is nothing wrong with this, as you just want to make certain you won't get a nullpointer exception.
I think it is reasonable to do.
With Extensions you can make it cleaner, but the basic concept would still be valid.
This code is totally valid, but I like to use the Null Coalesce Operator for avoid null type checks.
string someString = MagicFunction() ?? string.Empty;
if (someString.Length > 3)
{
// normal string, do whatever
}
else
{
// NULL strings will be converted to Length = 0 and will end up here.
}
Theres nothing wrong with this.
if(conditions are evaluated from left to right so it's perfectly fine to stack them like this.
This is valid code, in my opinion (although declaring a variable and assigning it on the next line is pretty annoying), but you should probably realize that you can enter the else-block also in the condition where the length of the string is < 3.
That looks to me like a perfectly reasonable use of logical short-circuitting--if anything, it's cheating with the language. I've only recently come from VB6 which didn't ever short-circuit, and that really annoyed me.
One problem to watch out for is that you might need to test for Null again in that else clause, since--as written--you're winding up there with both Null strings and length-less-than-three strings.
This is perfectly valid and there is nothing wrong with using it that way. If you are following documented behaviour for the language than all is well. In C# the syntax you are using are the conditional logic operators and thier docemented bahviour can be found on MSDN
For me it's the same as when you do not use parenthesis for when doing multiplication and addition in the same statement because the language documents that the multiplication operations will get carried out first.
Relying on short-circuiting is the "right thing" to do in most cases. It leads to terser code with fewer moving parts. Which generally means easier to maintain. This is especially true in C and C++.
I would seriously reconsider hiring someone who is not familiar with (and does not know how to use) short-circuiting operations.
I find it OK :) You're just making sure that you don't access a NULL variable.
Actually, I always do such checking before doing any operation on my variable (also, when indexing collections and so) - it's safer, a best practice, that's all ..
It makes sense because C# by default short circuits the conditions, so I think it's fine to use that to your advantage. In VB there may be some issues if the developer uses AND instead of ANDALSO.
I don't think it's any different than something like this:
INT* pNumber = GetAddressOfNumber();
if ((pNUmber != NULL) && (*pNumber > 0))
{
// valid number, do whatever
}
else
{
// On a null pointer, it drops to here, because (pNumber != NULL) fails
// However, (*pNumber > 0), if used by itself, would throw and exception when dereferencing NULL
}
It's just taking advantage of a feature in the language. This kind of idiom has been in common use, I think, since C started executing Boolean expressions in this manner (or whatever language did it first).)
If it were code in c that you compiled into assembly, not only is short-circuiting the right behavior, it's faster. In machine langauge the parts of the if statement are evaluated one after another. Not short-circuiting is slower.
Writing code cost a lot of $ to a company. But maintaining it cost more !
So, I'm OK with your point : chance are that this line of code will not be understood immediatly by the guy who will have to read it and correct it in 2 years.
Of course, he will be asked to correct a critical production bug. He will search here and there and may not notice this.
We should always code for the next guy and he may be less clever that we are. To me, this is the only thing to remember.
And this implies that we use evident language features and avoid the others.
All the best, Sylvain.
A bit off topic but if you rand the same example in vb.net like this
dim someString as string
someString = MagicFunction()
if not string.IsNullOrEmpty(someString) and someString.Length > 3 then
' normal string, do whatever
else
' do someting else
end if
this would go bang on a null (nothing) string but in VB.Net you code it as follows do do the same in C#
dim someString as string
someString = MagicFunction()
if not string.IsNullOrEmpty(someString) andalso someString.Length > 3 then
' normal string, do whatever
else
' do someting else
end if
adding the andalso make it behave the same way, also it reads better. as someone who does both vb and c' development the second vb one show that the login is slighty different and therefor easyer to explain to someone that there is a differeance etc.
Drux
What is the best was to evaluate an expression like the following:
(A And B) Or (A And C) Or (Not B And C)
or
(A && B) || (A && C) || (!B && C)
At runtime, I was planning on converting the above expressions to the following:
(True And False) Or (True And False) Or (Not False And True)
or
(True && False) || (True && False) || (! False && True)
Conditions:
1) The logical expression is not known until runtime.
2) The number variable and their values are not known until runtime.
3) Variable values are never null.
I know I could create a simple assemble with a class and a method that I generate at runtime based on the inputs, but is there a better way.
I have done this before. Use a string builder to write the code, then call the compiler. After that, you load the assembly and call the method.
Suggestions?
Thanks.
If you're using .NET3.5 then you can parse the text and create an abstract sytax tree using the Expression classes. Then create a suitable LambdaExpression instance and compile it into a delegate, which you can then execute.
Constructing a parser and syntax tree builder for this kind of fairly simple grammer is quite an interesting exercise, and will execute somewhat faster than invoking the compiler (and it's neater in my view as well).
If you're not using .NET3.5, then it's also not complicated to implement an interpreted abstract syntax tree yourself.
Be warned: the two final conditions you're talking about are not necessarily equivalent. The && operators in C# will use short-circuit evalution, while the logical And operator in VB does not. If you want to be sure the statements are equivalent, translate a user And to AndAlso and a user Or to OrElse.
For simple expresssions you probably won't notice a difference. But if the conditions can have side effects or if the performance difference between the two is a concern, this can be important.
You can use https://github.com/mrazekv/logicalparser
Its simply library to write logical expression (evaulated with precenednce table, allows to OR, NOT, AND operator and >, >=, <=, < on integer variables and = on string variables)
You can do this easily with:
a parser generator (like ANTLR, mentioned above) that takes boolean expressions as input and produces an infix list and
code to evaluate a Reverse Polish Notation stack.
The grammar looks something like this:
program: exprList ;
exprList: expr { Append($1); }
| expr OR exprList { Append(OR); }
| expr AND exprList { Append(AND); }
| NOT exprList { Append(NOT); }
| ( exprList ) { /* Do nothing */ }
;
expr: var { Append($1); }
| TRUE { Append(True); }
| FALSE { Append(False); }
;
To evaluate, you do this:
for each item in list
if item is symbol or truth value, push onto RPN stack
else if item is AND, push (pop() AND pop())
else if item is OR, push (pop() OR pop())
else if item is NOT, push (NOT pop())
result = pop()
For symbols, you have to substitute the truth value at runtime.
You can write a simple interpreter/parser. Use something like ANTLR and reuse existing grammars.
If you are using .NET 3.5, you can create a Lambda Expression. Then you can create a delegate from it and call as standard delegate/method.
On the internet is a lot of samples about Lambda Expressions.
One solution would be to assemble the expression as a string, and then send it SQL Server, or whatever your database is for evaluation. Replace the actual variables with 1=1 or 0=1 for True and False respectively, and you would end up with a query like this:
SELECT 1 WHERE (1=1 And 0=1) Or (1=1 And 1=1) Or (Not 0=1 And 1=1)
Then when you run the query, you get a 1 back when the result is true. May not be the most elegant solution, but it will work. A lot of people will probably advise against this, but I'm just going to throw it out there as a possible solution anyway.
This will not be the best answer, but I myself had this problem some time ago.
Here is my old code:
VB.Net - no warranty at all!
https://cloud.downfight.de/index.php/s/w92i9Qq1Ia216XB
Dim BoolTermParseObjekt As New BoolTermParse
MsgBox(BoolTermParseObjekt.parseTerm("1 und (((0 oder 1 und (0 oder 4))) oder 2)").ToString)
This code eats a String with multiple '(', ')', 'and', 'or' plus 'other things' and breaks down the logic to a boolean by replacing the things with boolean values.
therefore:
Whatever 'other things' I wanted to evaluate I had to put in Function resolveTerm()
at the comment "'funktionen ausführen und zurückgeben, einzelwert!"
in page 2.
There the only evaluation rightnow is "If number is > 1"
Greetings
Take a look at my library, Proviant. It's a .NET Standard library using the Shunting Yard algorithm to evaluate boolean expressions.
It could also generate a truth-table for your expressions.
You could also implement your own grammar.