Fog Creek Software
Discussion Board




Ternary Operators and Readability

Our lead developer frowns upon me using ternary operators of the following form:

int move = e.CommandName=="UP"?-1:1;

I happen to find them very useful especially when the alternative is a multiline if statement or switch statement. Moreover, they aren't *that* cryptic!

Do you all have coding standards that require the programmer to write more for the sake of readability?

David Seruyange
Tuesday, May 18, 2004

I have to admit, it takes a couple seconds to figure out what's going on, but I wouldn't have a hissy over it.

I'd just comment it and move along.

Walt
Tuesday, May 18, 2004

I think the addition of a few spaces makes it an order of magnitude more readable at first glance, but maybe it's just me:

int move = e.CommandName == "UP" ? -1 : 1;

Greg Hurlman
Tuesday, May 18, 2004

I use 'em all the time. Save a lot of space and are easy to understand. Sometimes helps if you put it in brackets like so and space them a bit better:

bar = (foo == 23 ? 1 : 0);

Matt
Tuesday, May 18, 2004

I love the ternary operator, but I'd make one change:

int move = (e.CommandName == "UP") ? -1 : 1;

It's not required by the code, but IMHO it makes it more readable. Imagine if instead of a literal you had:

int move = e.CommandName == e.TagValue ? -1 : 1;
is this

int move = (e.CommandName == e.TagValue) ? -1 : 1;
or
int move = e.CommandName == (e.TagValue ? -1 : 1);

?

The question isn't necessarily what it does - the question is: "Are what it does, what I think it does, and what the coder intended all the same thing?"

Putting in the parentheses goes a long way towards answering that question.

Philo

Philo
Tuesday, May 18, 2004

The only time we approve ternary is if the 'then/else' part is simple (e.g. the -1:1 in your case).

The last thing I want to see is stuff like:
foo = bar == 'joe' ? { sdfkdslfj; sfdsfasd; }:{sdfsdf;sdfsadsdf;}
etc.

MR
Tuesday, May 18, 2004

Yes. We don't use the ternary operator, because of readability concerns. We have many other restrictions.

In our work, we have software products that are maintained occasionally over periods of 10-15 years. Frequently, the development environment or computer language used vanishes while the product is still economically viable. Our customers are frustrated if we cannot support the software while they can make money selling systems including the software. I am frustrated as well, since selling an old product that is well tested and needs little support provides good profits. Therefore, we are very restrictive regarding programming practices, with the idea that programs should be easy to read and maintain for perhaps two decades, even for someone who never learned the language used. The software should also be easy to mechanically translate from one language to another, should that be needed.

In my experience, people that consider themselves software engineers dislike the restrictions. Their view seems to be that programming techniques and creativity in writing software matter, so restrictions are bad. Their view seems to be that a programmer is incompetent that does not know the programming language in detail.

The people who have scientific backgrounds like the restrictions. They tend not to be concerned about creativity in programming, but more with product features and capabilities. They like being able to pick up a product written by someone else at the company years ago, and easily add a feature or rework something in it. They want to spend their time on features, such as improving the recording speed of an acquisition system, rather than learning what they consider obscure features of yet another transient computer language. For them, the more brain-dead obvious the code, the better.

Dan Brown
Tuesday, May 18, 2004


They are kind of hard to debug.

With "if/else", the debugger steps on the line that is active.

"Saves space" is a silly excuse for anything.

It's not really any harder to use "if/else" and it's easier to understand.

(Ternary operators are discouraged by "Code Complete".)

njkayaker
Tuesday, May 18, 2004

sometimes they are easier to read. sometimes not.

what about statements like this:

printf("The operation has %s.", (result == OK ? "succeeded" : "failed"))

(and yes i believe the parens are necessary for readability.)

mb
Tuesday, May 18, 2004

Wow Dan, it sounds pretty restrictive in your environment.  Most ternary operators are documented quite well and consistent (I know C/C++ support the same facility, I think Java may be the same) across languages.

I know I'd have a hard time working in an environment of "assembly line" programming - what makes me love my job is being creative and solving problems.  I know that my falling in love with short, terse code isn't unique - it's the very roots of the definition hacker.

I understand that what I write now will come back - the software we write now is going to be in existence probably for a decade so I consider it an act of responsibility to make things "understandable" and well documented.  That's why I comment methods:

// swap two items in a datagrid
public void Swap(..){}

Finally, I think Paul Graham touches on something like this in his essay Hackers and Painters http://www.paulgraham.com/hp.html - programmers have less to do with "hard science" and more to do with creativity than one might initially think.

David Seruyange
Tuesday, May 18, 2004

In cases like this, I almost always use a function rather than a ternary expression. What's more readable:

int move = e.CommandName=="UP"?-1:1;

or

int move = GetMoveAmount( e.CommandName );

The advantages here are:

1) You have an actual NAME for this operation, so it's much easier to figure out at a glance what the intent of the code is.

2) You centralize that expression, so if it changes at some point you only need to change it ONCE.

3) If you need to use this expression elsewhere (and be honest, they always creep in) you can just re-use the existing function; less chance of making a mistake.

With a compiler that does inlining, you really don't pay anything in speed, so having the named function is generally a win.

Chris Tavares
Tuesday, May 18, 2004

How about:

  boolean isUp = e.CommandName=="UP";
  int move = isUp ? -1 : 1;

It's short, readable, and debuggable.  And (IMHO) much cleaner than:

  int move;
  if (e.CommandName=="UP") {
    move = -1;
  }
  else {
    move = 1;
  }


Just a thought...

Russell Thackston
Tuesday, May 18, 2004

Forget my last post, I like Chris' comments.

Russell Thackston
Tuesday, May 18, 2004

I don't agree that "saves space" is silly. I find that being able to see more code on my screen significantly helps my ability to comprehend it, whether I'm maintaining code or writing new code. For this reason, I favor the ternary operators for simple cases, such as the one presented; it occupies far less vertical space on the screen, leaving more room for the contextual code around it.

Rob Warner
Tuesday, May 18, 2004

I think ternary operators were great back in the days when when computers had < 8k of memory and ran at 1mhz.  :)
I don't see much need for the ? op now.  I would bet that modern compilers, such as Microsoft's C# compiler generate the same IL code for an equivalent "if" statement.

I strongly agree with njkayaker's comment about debugging, but if you want to save verticle space:

int move;
boolean isUp = e.CommandName=="UP";
if (isUp) move = -1;  else move = 1;

would be more readable IMHO.

madmax
Tuesday, May 18, 2004

So, combining Chris and Russell, we get:

int move = GetMoveAmount( e.CommandName );

...

int GetMoveAmount(char *cmd) {
    boolean isUp = cmd =="UP";
   return isUp ? -1 : 1;
}

Jim Rankin
Tuesday, May 18, 2004

I think whether a programmer uses the ternary operator indicates quite a bit about their style.  It might be fun to do a study and see what percentage of ternary operator uses do K&R style bracing.  My bet is ternary users tend to do K&R, and non-ternary do Allman.  I also bet non-ternary users tend to do huge, beautifully formatted function comments.

/********************************************
***
@name: foo
@arguments: s:java.lang.String
@return boolean
@author Joe Horker
@last_modified January 17th, 2004, 1:02 PM

This function takes a String, 's', and returns true if it equals "true" and false if it equals "false".

***
********************************************/
public boolean foo(String s)
{
  if("true".equals(s))
  {
    return true;
  }
  else
  {
    return false;
  }
}


or ternary style (but I wouldn't be surprised if they didn't even break out a function):

public boolean foo(String s) {
  return "true".equals(s) ? true : false;
}

Matt
Tuesday, May 18, 2004

Hmm...

public boolean foo(String s) {
  return "true".equals(s) ? true : false;
}

You don't see the irony there? Have you considered:

public boolean foo(String s) {
  return "true".equals(s);
}

? :)

Brad Wilson (dotnetguy.techieswithcats.com)
Tuesday, May 18, 2004

er, how about

bool foo(s)
{
  return ("true".equals(s));
}

I use ternary operators when they're more clear, braces on a line, one statement a line (except well known cases like for statements), and all if statements get braces--the statement

if (condition) a = 1; else a = 2;

is hard to read and pretty much guaranteed to break sometime during maintenece.

i find that long-winded function hard to read. and prone to side effects long term, which might be good or bad. (e.g. add some code to make it case insensitive=good,  call some unrelated code to cause persistence to occur=bad).

mb
Tuesday, May 18, 2004

Brad, good point, bad example on my part.  :)

Matt
Tuesday, May 18, 2004

int y_distance_to_move = (e.CommandName=="UP") ?-1 : 1;
or
int move = GetMoveAmount( e.CommandName );


I prefer the first one. It is far easier to read and I don't have to go treking off to some other function tto find out what the heck is going on.

Dennis Atkins
Tuesday, May 18, 2004

GetMoveAmount( e.CommandName ); has advantages.

What happens when CommandName == "SIDEWAYS" ?


The only time I like the ternary operator is in this form:
( (a) ? c : d)

And only if it fits cleany in about 40 characters or less. So the first example at the top would be ok if you added parens to make it more obvious.

NathanJ
Tuesday, May 18, 2004

Of course, the name GetMoveAmount was just what I came up with after only seeing the one expression; hopefully in a real application the function could be named something that fit better with the problem domain.

I still say that having a named function rather than an anonymous (and potentially complicated) expression is the way to go. Guess we'll just have to agree to disagree on this one.

Chris Tavares
Tuesday, May 18, 2004

Interesting. I did not know so many people were just a priori against the ternary operator. I tend to use what makes the most sense to me at the time. One thing I NEVER do is

if joe
  do this

rather
if(joe){
  do
}

or if it's an assignment and simple:

a = true === true ? true : false;

But that does not mean I ALWAYS use the ternary operator.

Personally I happen to like the ternary and I dislike code that is verbose.  Don't make a mistake of substituting verbosity for clarity. I think what is true in writing prose is the same in programming. It takes more time to say it in less words. However, I am not arguing for obfuscation.

I strive to always put comments which say what I want to do as opposed to describing what I am going to do as that is right in front of your eyes.  I think that if I write unobfuscated code yet terse then I or anyone else will understand it quicker.

I have taken some code and just erased all the comments and the line breaks and only then would I work on it as I don't like stuff which just gets in the way as code with too many comment always tends to do imho.

me
Tuesday, May 18, 2004

Just because...

There are some cases where the ternary operator is required (at least in C++). If you're reference happy (and who isn't), then you can use a ternary operator like this:

const string &str=bCondition ? string1 : string2;

It would be difficult to affect the value of the reference any other way (if-else wont work; you'd need a special function).

Ternary is a fact of life in a C syntax derived language. Prohibiting its use out-right on a project feels akin to prohibiting the use of contractions in English writing.

Mark L. Smith
Tuesday, May 18, 2004

I like the way Cline Marshall explains it:

http://users.utu.fi/sisasa/oasis/cppfaq/coding-standards.html#[25.4]

Anonymouche
Tuesday, May 18, 2004

Yep, as that points out, a very common and useful use for these things is small chunks of boring string-building code that really shouldn't take up much space due to their triviality, eg

string = 'Freddy has ' + str(n) + (n == 1 ? ' bollock' : ' bollocks') + ' and he knows what to do with them'

rather than

string = 'Freddy has'
string += str(n)
if (n == 1):
  string += 'bollock'
else:
  string += 'bollocks'
string += ' and he knows what to do with them'

Matt
Tuesday, May 18, 2004

I too use the ternary op for string concatenation cases like that, though I can't help but point out that it's an internationalization nightmare waiting to happen, if such things are a consideration for the kind of projects you work on...

John C.
Wednesday, May 19, 2004

From the C++ FAQ (http://www.parashift.com/c++-faq-lite/coding-standards.html#faq-27.5) -

Code must be written to be read, not by the compiler, but by another human being.


Wednesday, May 19, 2004

string = 'Freddy has ' + str(n) + (n == 1 ? ' bollock' : ' bollocks') + ' and he knows what to do with ' + (n == 1 ? 'it' : 'them')

i like i
Wednesday, May 19, 2004

>> Code must be written to be read, not by the compiler, but by another human being.

INTERCAL.

Alex
Wednesday, May 19, 2004

The one thing nobody has touched on is that if/else is a statement and ?: is an expression. These are parsed differently by the compiler. With modern multipass optimizing compilers, there are few if any cases where this makes a real difference but if you want to write an LR(1) C parser it makes quite a bit of difference. Having expression level and statement level conditional evaluation can greatly simplify your parser.

Trevor Clarke
Thursday, July 29, 2004

*  Recent Topics

*  Fog Creek Home