Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Let's suppose I have some sort of form that automatically performs a copy procedure when the user either focuses on a textbox, or highlights some text.

Let's suppose that the user has a preference of copying on focus or copying on highlight. By default, it copies on highlight... which leads us to this code

if(copyOnFocus ? hasFocus : isHighlighted) {
   copy();
}

I understand this code without any problem, but I have this nagging feeling that this is a bad idea because I've never seen a ternary inside of an if condition before.

Is this ok, or should it be refactored? If it needs to be refactored, what would you suggest?

share|improve this question
1  
Is it easy to read? Is the alternative easier to read? – Loki Astari Jan 20 '12 at 20:53
I like this question. There are three or four answers below which I consider clearer than the code in the question, so good questin. – Andy Jan 22 '12 at 2:40
Personally, I find this the easiest; everything else is more verbose, is awkward and/or leaves variables littering the local namespace, etc.. However, this is atypical and does not scale well as the complexity of the ternary increases, so it'd depend on who you're working with and what the rest of the code base looks like. – Rex Kerr Jan 22 '12 at 5:31

8 Answers

up vote 24 down vote accepted
bool shouldCopy = (copyOnFocus ? hasFocus : isHighlighted);
if (shouldCopy) copy();

There: no more nested conditions. Happiness ensues.

share|improve this answer
9  
How is that an improvement? – Winston Ewert Jan 21 '12 at 2:03
2  
I agree, this is just the same code but split over two lines, and with one extra variable (that's outside the scope it is used in). – Anton Golov Jan 21 '12 at 2:43
2  
@WinstonEwert: There's nothing wrong with his original code, IMO, but if he wants to move the ternary outside the if condition this is a way to do it. – Daniel Jan 21 '12 at 2:58
10  
This sort of variable is called an "explaining variable". This looks like a very reasonable use of such a variable, if you're worried about the readability of the original example. – TehShrike Jan 21 '12 at 6:21
2  
The extra variable adds clarity for the reader. If I were doing this code review, that's the comment I would make. This isn't 1960 anymore, declaring a variable just for the sake of readability won't run us out of memory. – Andy Jan 22 '12 at 2:31
show 4 more comments

As you mention - I've actually never seen this before.

It is completely logical and would work just fine - but I imagine that not all programmers would find this easy to read and debug.

My general recommendation would be to refactor it and move the decision making process to a new function - like this:

bool shouldCopy() {
    if (copyOnFocus)
        return hasFocus;
    else
        return isHighlighted;
}

This also makes it a lot easier to set break points when debugging.

share|improve this answer
1  
IMO, this (unnecessarily)leads to more lines of code, and seems to be more of an objection to the ternary operator in general, than the use of a ternary operator inside an if conditional. I have seen people somewhat object to the use of a ternary operator before but assuming that is not the case in the OP's team, I would think that Daniel's solution is probably more preferable. – Vijay Kotari Jan 21 '12 at 7:53
1  
@James true - the focus of my response is to encapsulate decision making. If we should take scope (or with this post - even programming language) into consideration we couldn't really make any refactoring at all. – mbanzon Jan 21 '12 at 10:07
3  
@DavidWallace: The more verbose your code is, the longer it takes for the next developer to read it and grok what's going on. I disagree. Shorter code is not always easier to read. – Joren Jan 21 '12 at 18:45
1  
I have to agree with Joren - and I generally think that the point of encapsulating code in functions is for reuse only is not the whole truth. I don't find anything wrong with putting different parts of a complex structure into different separate functions if it seems logical - this is usually something like advanced decision making (like this example - but maybe a bit more complex - like 10-20 lines of code). The fact that the resulting functions are all only called once weighs little compared to the improved readability of the main function. – mbanzon Jan 21 '12 at 19:41
2  
@Joren - OK, I see what you mean, and admit that you are right; I should have worded that differently. At work, I am in a team of Java developers. All too frequently I see verbosity for no gain in legibility, both in comments and in code; and this makes me grumpy. One of my pet hates is the addition of a one-off extra method that IMO should have been inlined. I guess when I read mbanzon's answer, I saw the opportunity for a rant, and got carried away. – David Wallace Jan 21 '12 at 23:25
show 9 more comments

You can rewrite this using && and || if you want. Basically, you want the loop to execute if copyOnFocus and hasFocus are true, or if copyOnFocus is false and isHighlighted is true. This can be phrased as

if ((copyOnFocus && hasFocus) || (!copyOnFocus && isHighlighted))
    // ...

Some may find this more readable, although it doesn't seem much better to me. If you don't care about copyOnFocus being false as long as isHighlighted is true:

if ((copyOnFocus && hasFocus) || isHighlighted)
    // ...

This changes the semantics of the code, but may be valid depending on what you know about those variables.

Personally, I find this about as hard to read as the original idea: splitting it off into a function may indeed be best, but I wouldn't consider it very big of a deal.

share|improve this answer
2  
Yeah, but this is Karnaugh-mapping. The original was more legible. The only punctuation was ? : – smci Jan 21 '12 at 13:05
1  
Personally I find this the easiest to read. Reading off the conditions directly states what the if statement is testing, unlike a nested ternary – Martin Jan 22 '12 at 1:22
I agree. This seems to be the most clearly stated intent of the code. There's an option the user can set (copyOnFocus) and you can see that depending on the option it will copyOnFocus or copyOnHighlight. – Andy Jan 22 '12 at 2:37

No, not bad: your ternary inside if is good: concise yet readable. It's good to teach people who haven't seen it.

If a bug requires the details of your line to be breakpointed, temporarily substitute more verbose code, but remove it later.

share|improve this answer

Your intuitions are right in telling you that this is bad. Mixing two different types of conditional statements (if (condition) { ... } and condition ? ... : ...) makes it extremely confusing to read.

I recommend refactoring so it only uses one type of conditional expression. Something like this:

(copyOnFocus ? hasFocus : isHighlighted) ? copy() : doNothing();
share|improve this answer
7  
I find this way less readable than the original code, and am considering downvoting it. It also requires that copy() and doNothing() have the same non-void return type. As a rule of thumb, I would use the ternary operator only when both legs of it are free of side effects - that is, you're evaluating some expression n > 0 ? "positive" : "zero or negative"; not to control which chunks of code do and don't run. In answer to Peter's question, a ternary operator within the if() is perfectly fine, and more readable than any of the answers that have been posted here so far. – David Wallace Jan 21 '12 at 11:30

There are many ways to skin the cat. I like both the answer by @mbanzon and the one by @Daniel. Since you posted only a small section of the code, I do not know whether these variables are local (most likely) or global, and what the rest of your function looks like. Here is one way (anyone who can add two number in their head should be able to do the DeMorgan's arithmetic as well):

...
if (copyOnFocus)
{
    if (!hasFocus)
    {
        return; // or continue/break if inside a loop
    }

    if (!isHighlighted)
    {
        return; // or continue/break if inside a loop
    }
}

copy();
...

Now, some people hate multiple return statements. I am not one of them; I think they are fine. Having a single bool shouldCopy() function is cleaner in that ... if I decided to use break or continue instead of return, then I would only need to do it in one place. The downside is: if the variables are local, then all three of them would need to be passed in to the shouldCopy(,,) function, and that is arguably too verbose (though the proponents of the functional programming would probably not mind).

share|improve this answer
I personally don't like multiple returns, but I do think this is clearer than the teriary in the if so I think it deserves an upvote. – Andy Jan 22 '12 at 2:39

I've never seen a ternary operator inside an if condition before — and I don't think there's anything wrong with it — but it did give me pause for a bit when I first saw it. I don't think any of the more complicated answers with intermediate variables or functions add any clarity.

You might consider writing it like this:

if (copyOnFocus
        ? hasFocus
        : isHighlighted)
{
    copy();
}

although I'm not really sure how much of an improvement that is, since the original was pretty clear to me in the first place (after a couple of seconds of initial surprise).

share|improve this answer

It entirely depends on the skill-level of all programmers that need to understand this.

I have no problem reading this. You don't either. But someone else might. If you are sure that all programmers in your org are comfortable with such things, there is no problem here at all.

However if you think someone might not understand this, you can add a comment. Don't explain, how this works - explain what it means! (Just like you did in your question).

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.