I don't like this... Is this cheating the language? - c#

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

Related

Is there a way to use less than on Strings?

Using a string.CompareTo(string) i can get around this slightly but is not easy to read and i have read on that locallity settings might influence the result.
Is there a way to just simply use < or > on 2 Strings in a more straightforward way?
You can overload operators but you seldom should. To me "stringA" > "stringB" wouldn't mean a damn thing, it's not helping readability IMO. That's why operator overloading guidelines advise not to overload operators if the meaning is not obvious.
EDIT: Operator Overloading Usage Guidelines
Also, in case of String I'm afraid you can't do it seeing as you can put operator-overloading methods only in the class in which the methods are defined.
If the syntax of CompareTo bothers you, maybe wrapping it in extension method will solve your problem?
Like that:
public static bool IsLessThan(this string str, string str2) {
return str.Compare(str2) < 0;
}
I still find it confusing for reader though.
The bottom line is, you can't overload operators for String. Usually you can do something like declaring a partial and stuffing your overloads there, but String is a sealed class, so not this time. I think that the extension method with reasonable name is your best bet. You can put CompareTo or some custom logic inside it.
CompareTo is the proper way in my opinion, you can use the overloads to specify culture specific parameters...
You mention in a comment that you're comparing two strings with values of the form "A100" and "B001". This works in your legacy VB 6 code with the < and > operators because of the way that VB 6 implements string comparison.
The algorithm is quite simple. It walks through the string, one character at a time, and compares the ASCII values of each character. As soon as a character from one string is found to have a lower ASCII code than the corresponding character in the other string, the comparison stops and the first string is declared to be "less than" the second. (VB 6 can be forced to perform a case-insensitive comparison based on the system's current locale by placing the Option Compare Text statement at the top of
the relevant code module, but this is not the default setting.)
Simple, of course, but not entirely logical. Comparing ASCII values skips over all sorts of interesting things you might find in strings nowadays; namely non-ASCII characters. Since you appear to be dealing with strings whose contents have pre-defined limits, this may not be a problem in your particular case. But more generally, writing code like strA < strB is going to look like complete nonsense to anyone else who has to maintain your code (it seems like you're already having this experience), and I encourage you to do the "right thing" even when you're dealing with a fixed set of possible inputs.
There is nothing "straightforward" about using < or > on string values. If you need to implement this functionality, you're going to have to do it yourself. Following the algorithm that I described VB 6 as using above, you could write your own comparison function and call that in your code, instead. Walk through each character in the string, determine if it is a character or a number, and convert it to the appropriate data type. From there, you can compare the two parsed values, and either move on to the next index in the string or return an "equality" value.
There is another problem with that, I think:
Assert.IsFalse(10 < 2);
Assert.IsTrue("10" < "2");
(The second Assert assumes you did an overload for the < operator on the string class.)
But the operator suggests otherwise!!
I agree with Dyppl: you shouldn't do it!

Nothing != null - or does it?

Recently in a previous project I came across a peculiar difference between VB.NET and C#.
Consider the following C# expression which:
null <= 2
This expression evaluates to False which is what I would expect.
Then the corresponding VB.NET expression:
Nothing <= 2
I was surprised to learn that this expression actually evaluates to True
It seems like a fairly fundamental design decision between the two languages and it certainly caught me out.
Is anyone able to tell me why?
Are null and Nothing one and the same?
If so, why do they behave differently?
Nothing in VB evaluates to the default value for a given type. (See this link for details.)
For an integer comparison (which the compiler will assume from the right hand operand), Nothing will thus be 0. 0 <= 2 is true for more obvious reasons :-)

.NET C# switch statement string compare versus enum compare

I'm interested in both style and performance considerations. My choice is to do either of the following ( sorry for the poor formatting but the interface for this site is not WYSIWYG ):
One:
string value = "ALPHA";
switch ( value.ToUpper() )
{
case "ALPHA":
// do somthing
break;
case "BETA":
// do something else
break;
default:
break;
}
Two:
public enum GreekLetters
{
UNKNOWN= 0,
ALPHA= 1,
BETA = 2,
etc...
}
string value = "Alpha";
GreekLetters letter = (GreekLetters)Enum.Parse( typeof( GreekLetters ), value.ToUpper() );
switch( letter )
{
case GreekLetters.ALPHA:
// do something
break;
case GreekLetters.BETA:
// do something else
break;
default:
break;
}
Personally, I prefer option TWO below, but I don't have any real reason other than basic style reasons. However, I'm not even sure there really is a style reason. Thanks for your input.
The second option is marginally faster, as the first option may require a full string comparison. The difference will be too small to measure in most circumstances, though.
The real advantage of the second option is that you've made it explicit that the valid values for value fall into a narrow range. In fact, it will throw an exception at Enum.Parse if the string value isn't in the expected range, which is often exactly what you want.
Option #1 is faster because if you look at the code for Enum.Parse, you'll see that it goes through each item one by one, looking for a match. In addition, there is less code to maintain and keep consistent.
One word of caution is that you shouldn't use ToUpper, but rather ToUpperInvariant() because of Turkey Test issues.
If you insist on Option #2, at least use the overload that allows you to specify to ignore case. This will be faster than converting to uppercase yourself. In addition, be advised that the Framework Design Guidelines encourage that all enum values be PascalCase instead of SCREAMING_CAPS.
I can't comment on the performance part of the question but as for style I prefer option #2. Whenever I have a known set of values and the set is reasonably small (less than a couple of dozen or so) I prefer to use an enum. I find an enum is a lot easier to work with than a collection of string values and anyone looking at the code can quickly see what the set of allowed values is.
This actually depends on the number of items in the enum, and you would have to test it for each specific scenario - not that it is likely to make a big difference. But it is a great question.
With very few values, the Enum.Parse is going to take more time than anything else in either example, so the second should be slower.
With enough values, the switch statement will be implemented as a hashtable, which should work the same speed with strings and enums, so again, Enum.Parse will probably make the second solution slower, but not by relatively as much.
Somewhere in the middle, I would expect the cost of comparing strings being higher than comparing enums would make the first solution faster.
I wouldn't even be surprised if it were different on different compiler versions or different options.
I would definitely say #1. Enum.Parse() causes reflection which is relatively expensive. Plus, Enum.Parse() will throw an Exception if its not defined and since there's no TryParse() you'd need to wrap it in Try/Catch block
Not sure if there is a performance difference when switching on a string value versus an enum.
One thing to consider is would you need the values used for the case statements elsewhere in your code. If so, then using an enum would make more sense as you have a singular definition of the values. Const strings could also be used.

SubSonic RESTHandler Question

I'm playing with the SubSonic RESTHandler for the first time and it's awesome... There is one quirk tho, that I'm curious about.
RESTHandler.cs (line 319):
//if this column is a string, by default do a fuzzy search
if(comp == Comparison.Like || column.IsString)
{
comp = Comparison.Like;
paramValue = String.Concat("%", paramValue, "%");
}
This little blurp of code forces all searches on string columns to wildcard searches by default. This seems counter intutive, since you've provided a nice set of comparisons we can add to a parameter (_is, _notequal, etc...). Is there a reason this was done? The EvalComparison uses "Comparison.Equals" as it's default, so unless a like is explicitly needed the " || column.IsString" looks like it should be removed since it breaks the ability to use different types of comparisons.
This was driving me crazy, since you can't do a "WHERE Field = X" without modifiying code...
Just curious if this is more of a feature than a bug...
Thanks!
Zach
It's because this is a LIKE operation which for a DB usually allows string operations. The feeling at the time was that if you wanted equals you could just use that.
It's been a while since I've touched this code - if you'd be kind enough to open a bug I'll take a look at it.
It does indeed look like a feature. It's based on the idea that, if I am searching for a string in a column without the wildcards, I must match the string exactly or I get no hits. I suspect that this was done to make programming search textboxes easier.

Is this a reasonable use of the ternary operator? [closed]

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

Categories