# Tuesday, March 11, 2008

Like many tips & tricks concerning programming languages, what I will present here will be so utterly obvious to some C# developers, but could be an eye-opener to others.

How often do you write something like this?

        if (token == "A")
            tokenNumber = 1;
        else if (token == "B")
            tokenNumber = 4;
        else if (token == "C")
            tokenNumber = 5;
        else if (token == "X")
            tokenNumber = 10;
        else
            tokenNumber = 20;


How about writing it like this?

      tokenNumber = (token == "A") ? 1:
                    (token == "B") ? 4:
                    (token == "C") ? 5:
                    (token == "X") ? 10:
                                     20;


It's the same thing, but it looks cleaner, and the generated IL code is almost the same (it's even a bit shorter).

The reason this works is because the ternary operator (?:) is one of the few right-associative operators in C#. The other 2 are the assignment operator (=) and the lambda operator in C# 3.0 (=>)

kick it on DotNetKicks.com
Tuesday, March 11, 2008 2:33:05 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [24] -

Tuesday, March 11, 2008 3:10:39 PM (W. Europe Standard Time, UTC+01:00)
Of course a switch statement would be still yet cleaner ...
Tuesday, March 11, 2008 3:16:31 PM (W. Europe Standard Time, UTC+01:00)
In this particular case you could, but not if you have something like this:

tokenNumber = (number < 5) ? 1:
(number >5 && number <10) ? 4:
(number == 10) ? 5:
(number == 11) ? 10:
20;
Tuesday, March 11, 2008 3:25:01 PM (W. Europe Standard Time, UTC+01:00)
I hate those if-else statements.
I would prefer switch statement if I can, otherwise use a Dictionary.

Something like

public int GetNumberFromToken(string token)
{
const int defaultTokenNumber = 20;

Dictionary<string, int> tokenToNumberMap = new Dictionary<string, int>();
tokenToNumberMap.Add("A", 1);
tokenToNumberMap.Add("B", 4);
tokenToNumberMap.Add("C", 5);
tokenToNumberMap.Add("X", 10);

return tokenToNumberMap.ContainsKey(token) ? tokenToNumberMap[token] : defaultTokenNumber;
}

JD
Tuesday, March 11, 2008 3:33:15 PM (W. Europe Standard Time, UTC+01:00)
Yes, but again, this only works if you do equality comparisons. Not if you have other true/false conditions you want to check.
Tuesday, March 11, 2008 6:26:04 PM (W. Europe Standard Time, UTC+01:00)
That is way cleaner. So basically you're just chaining ternary operators together? Reminds me of the syntax in F# a little bit.
Tuesday, March 11, 2008 6:44:22 PM (W. Europe Standard Time, UTC+01:00)
I dont mean to hate but I can not believe that this made it to dzone. What were people smoking when they kicked this up? I HATE ternary operators because in the real world most of the code you see is like the snippet second commentator posted. Every decent programmer knows about these ternary crappy operator but tends to not use them because they get confusing!

i'll stick with the traditional if, else which is more legible or switch statements in the case that you've presented.
Bhaarat
Tuesday, March 11, 2008 6:45:55 PM (W. Europe Standard Time, UTC+01:00)
Chaining If/else statements is something that u learn is a no no after programming for a couple years. First, C# can optimize switch statements making them more efficient (not always the best choice, but in ur example that is clearly better)

If ur more than a "faint of heart" programmer. This should be in the Strategy Design pattern. Yeah it increases the code a bit (like most design patterns) however once that method passes your TDD tests the beauty is that it never gets touched again as the method/classes are not coupled.
Bart Czernicki
Tuesday, March 11, 2008 6:59:35 PM (W. Europe Standard Time, UTC+01:00)
Bart, you could not use a switch statement in this case because the strings that the variable is being compared to are not constants.
Gabriel
Tuesday, March 11, 2008 7:12:27 PM (W. Europe Standard Time, UTC+01:00)
Of course if you use Magical Number and magical letters, it seems easier that way.

However, I agree with JD.

Please use Dictionary. For god sake, put those letters in a configuration somewhere and add them to a dictionary. Even better, build a section in your Web.Config (or App.Config) that contains those value and dynamically load them into a dictionary at load time. No more "if" loop.

Using already existing structure is a best practice.
Arch4ngel
Tuesday, March 11, 2008 7:44:51 PM (W. Europe Standard Time, UTC+01:00)
Well, for dictionaries, it's a bit of a mixed bag.

The example posted by JD is just scary bad. Building an entire dictionary just to locate one value? That's going to run SEVERAL orders of magnitude slower that any other version here. Remember, the the advantage of a dictionary is that is finds items in O(ln N) time. But building a dictionary is necessarily an O(N) operation.

Now, if we had a large number of values to test (10 to 20 at least), AND we could build the dictionary once per session (easy in Winforms; a bit trickier in WebForms) then using a dictionary is the best option.

I wouldn't necessarily put the values in a app/web.config. Basically, if there are enough values for a dictionary, then there are probably too many for an app.config. They probably should be read from a database. Also, remember that a magic number is a magic number no matter where it is. If either side of the mapping is an enum (usually a very good bet), then the mapping must be done in code. If you try putting enum values in the app.config, there it's the one with magic numbers.

Tuesday, March 11, 2008 8:09:02 PM (W. Europe Standard Time, UTC+01:00)
I like the idea of using a dictionary or strategy pattern, but isn't there some way we can shoe-horn a fricken XML config file into this 5 lines of code? Could maybe dependency injection be used? Or a web service? Here's hoping.
commenter
Tuesday, March 11, 2008 8:10:44 PM (W. Europe Standard Time, UTC+01:00)
Oops sorry, I wasnt parodying the immediately preceding comment there - I hadnt noticed it. Serendipity!
commenter
Tuesday, March 11, 2008 8:50:28 PM (W. Europe Standard Time, UTC+01:00)
Great way to confuse junior members of the team.
James L
Tuesday, March 11, 2008 10:44:30 PM (W. Europe Standard Time, UTC+01:00)
The ternary operator has always been a cryptic construct that has been met with much controversy. I prefer the more verbose form, as junior members and non-coding parties have a higher chance of understanding the code quickly.

I am really not so concerned with "programming efficiency" from a keystroke standpoint, or from a "oh I saved 5 lines of IL with this method" standpoint either. Obviously if something is going to be looped over it must be efficient, however. "source code efficiency" at the price of legibility only leads to higher lifetime support costs, either in bugs that need to be fixed, or time wasted by people trying to figure out clever code.

Legibility prevents bugs, and I find bugs far more troubling than taking up an extra 5 lines of code by doing something verbosely.

The compiler has your back on this one.
Eric
Tuesday, March 11, 2008 10:48:10 PM (W. Europe Standard Time, UTC+01:00)
In this particular case, nobody will deny that the second piece of code is more readable than the first.

I agree that in most other cases it is better to stick with classic constructs.

This post is merely a pointer to a lesser-known aspect of the ternary operator.

Besides, controversy is a good thing :-)
Wednesday, March 12, 2008 2:15:23 PM (W. Europe Standard Time, UTC+01:00)
I think the example is pretty neat. Obviously not for every situation. I agree with the comment further above, the Dictionary is maybe overkill for such a short list, but good idea for longer stuff.
I think even somebody that has no idea about the ternary operators can understand the example.
Thursday, March 13, 2008 3:57:35 AM (W. Europe Standard Time, UTC+01:00)
Although most of us are C# developers, VB.NET has their "Tertiary" operator as well called IIF. However, IIF doesn't work the way a C/C++/C# dev would expect. VB.NET will actually interpret all three statements, the validation, the true condition, and the false condition, regardless of True or False. This is particularly nasty if you're inlining a If-Not-Null check (Common in DB Access/Mapping code).

Just a heads up.
Lucas Goodwin
Monday, March 17, 2008 8:46:30 PM (W. Europe Standard Time, UTC+01:00)
What a fuss over a stupid article about a simple language feature that few people know about. The code sample I gave is not complicated, and cleaner than the if-then-else way of writing it, *IN THIS SPECIFIC CASE*. And in this case, even if someone doesn't have a clue about what the ternary operator does, he/she will still capture the meaning of that piece of code, because of the way it is written.

I would never recommend this pattern for performing complex conditional assignments. It's just a piece of code showing the "special" behavior of a right-associative operator such as the ternary operator.
Wednesday, March 19, 2008 1:03:00 AM (W. Europe Standard Time, UTC+01:00)
I don't like the 'else if' constructs either. Any modification of a single statement in such a chain may affect all the following statements. Also, when inspecting such code, one has to go through all the statements or risks missing an important detail.

In simple cases the switch statement solves the problem.

For more complex cases I wish to suggest the following construct:
int a = 3;

for ( ;; )
{
if ( a < 2 )
{
Console.WriteLine( a );
break;
}

if ( a >= 2 && a < 5 )
{
Console.WriteLine( a ); // this will be executed
break;
}

if ( a >= 5 )
{
Console.WriteLine( a );
break;
}

} // for

It involves a bit more code, of course, but is more clear and robust, IMHO.
Ted K
Wednesday, March 19, 2008 4:46:11 AM (W. Europe Standard Time, UTC+01:00)
WTF?

I have been programming for more than 2 decades and I have never seen the ternary operator abused in such a heinous manner!

You are the weakest link, good-bye!

Bob The Old Geezer
Wednesday, March 19, 2008 6:24:30 AM (W. Europe Standard Time, UTC+01:00)
Code looks good and understable.Best utilization of ternary operator.


public class test1 {

/**
* @param args
*/
public static void main(String[] args) {
int iInt = 13;
int iJ = (iInt == 10) ? 10
: (iInt == 20) ? 20
: (iInt == 30) ? 30
:40;
System.out.print(iJ);
}
Vabhav Jain
Wednesday, March 19, 2008 6:40:39 AM (W. Europe Standard Time, UTC+01:00)
for similar code simple and nice. Why don't use it?
Wednesday, March 19, 2008 8:07:08 AM (W. Europe Standard Time, UTC+01:00)
Mr Old Geeser, since when is the length of your career a measure for your intelligence? It certainly doesn't give you the right to be condescending using an unverifiable identity.

Read my earlier comment about the true spirit of this post.
Wednesday, March 19, 2008 5:19:14 PM (W. Europe Standard Time, UTC+01:00)
Philippe, thanks for a nice little construct.
I can't wait to have the opportunity to use it!

This reminds me of other things which at first
glance look cryptic but at second glance look
beautiful while still being simple.

e.g. ZoneLayout, Stripes & XStream
Comments are closed.