-1

What are the merits and demerits of the following two code snippets:

return n==0 ? 0 : n==1 ? 1 : fib(n-1) + fib(n-2);

and

 if(n==0)  
    return 0;
 if(n==1)
    return 1;
 return fib(n-1) + fib(n-2);

for calculating the nth letter in the Fibonacci sequence?

Which one would you favour and why?

Tom
  • 6,601
  • 12
  • 40
  • 48
  • 6
    I prefer `return round(pow(GOLDEN_RATIO,n) / sqrt(5));` – kennytm Feb 16 '10 at 17:39
  • 1
    The nth letter? Is this the Roman version of the Fibonacci sequence? – Mark Byers Feb 16 '10 at 17:40
  • 2
    The second one, first of all because the first one is wrong (fib(n-1) + fib(n+1)?) and second because there's no point in doing that, it just makes the code unreadable. – IVlad Feb 16 '10 at 17:41
  • 1
    http://stackoverflow.com/questions/160218/to-ternary-or-not-to-ternary – Jørn Schou-Rode Feb 16 '10 at 17:50
  • @IVlad, I believe there is makes it unreadable, but for simple null-checks and such, the conditional operator really helps to make your code more concise and readable to any programmer worth his salt (read: knows how to use the conditional operator) – Earlz Feb 16 '10 at 17:51
  • BTW, this is a terrible way to calculate Fibonacci numbers from a computational point of view, with the double recursion. Just thought I'd mention it. – David Thornley Feb 16 '10 at 18:24
  • @roe, @Jørn Schou-Rode, @Earlz - May I know which close reason did you choose? **exact dup** or **subjective and argumentative**? I was asking priority of close votes on meta here http://meta.stackoverflow.com/questions/39658/priority-of-close-votes, thanks – YOU Feb 17 '10 at 03:17

14 Answers14

9

The first one is the devil and must be purged with fire.

Cory Petosky
  • 12,458
  • 3
  • 39
  • 44
6

I would favour:

return n <= 1 ? n : fib(n-1)+fib(n-2);
Sani Huttunen
  • 23,620
  • 6
  • 72
  • 79
4

I would prefer writing:

if (n == 0) {
    return 0;
}
else if (n == 1) {
    return 1;
}
else {
    return fib(n-1) + fib(n-2);
}

This is very readable code. I don't even like omitting braces as the code is not that readable and when you maintain code that omits braces, you easily make bugs.

Lauri
  • 4,670
  • 2
  • 24
  • 17
  • 1
    I agree, in my opinion, brackets should never ever be omitted. – dassouki Feb 16 '10 at 18:07
  • I agree, don't omit braces. (Although I prefer the opening brace on a separate line) – Liz Albin Feb 16 '10 at 18:53
  • I disagree, please omit braces. Adding braces on one-line if statements is equivalent to adding semicolons to the end of every line in Python. – Cory Petosky Feb 16 '10 at 19:05
  • This is just an matter of opinion. The only exception that I allow myself to do is that I can test is parameters are valid like this: int foo(int bar) { if (bar < 0) throw new IllegalArgumentException(); } It requires that the if statement really is on-line statement and does not have new line before the throw statement. One of my favorite quotes is from Kent Beck: "I'm not a great programmer, I'm a pretty good programmer with great habits." I have seen programmers to fail to implement working code/fixing bugs because of this just too many times. – Lauri Feb 17 '10 at 08:09
2

Everything in life is a matter of equilibrium. Finding the right compromise between two opposite ends of the spectrum. Optimality is a scoring function that is highly dependent on the evaluator, and the situation, but you should strive for the sweet spot in everything.

Programming is not different. you should evaluate

  • simplicity
  • terseness
  • efficiency
  • practicality
  • artistic freedom of expression
  • time constraints

and find the sweet spot.

Your first construct is clearly powerful and geeky, but definitely not easy to understand.

Stefano Borini
  • 138,652
  • 96
  • 297
  • 431
1

I prefer the second over the first, mostly for readability.

The second "reads" well - it has the code broken up, so it reads most like English. This will make it easier to understand for many developers.

Personally, I find multiple, chained ternary operations difficult to follow at times.

Also, I personally find "conciseness" to be a poor goal, in most cases. Modern IDEs make "longer" code much more manageable than it used to be. I'm not saying you want to be overly verbose, but trying to be concise often causes an increase in the maintenance effort, in my experience.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
1

If you're asking for readability, I'd prefer the second option because it doesn't contain the (double!) ternary operator. Usually you're writing code that other people also have to read, and from the second snippet, it's clear at first sight what the function does. In the first snippet though, one has to resolve both ternary operators "in your head" and additionally think about associativity (I'd think about that automatically because parentheses are missing).

But anyway, you could reduce the two if statements to one:

if(n <= 1) return n;
return fib(n-1) + fib(n-2);
AndiDog
  • 68,631
  • 21
  • 159
  • 205
1

Of the two, the second is easier to understand at a glance. However, I'd consolidate it as

if (n <= 1) 
  return n;
else
  return fib(n-1) + fib(n-2);

Or, if you're not into multiple returns:

if (n > 1)
  n = fib(n-1) + fib(n-2);
return n;
John Bode
  • 119,563
  • 19
  • 122
  • 198
1

I often find that indentation can make the multiple-ternary operators a lot more readable:

return n == 0 ? 0 :
       n == 1 ? 1 :
                fib(n-1) + fib(n-2); 
Dan Vinton
  • 26,401
  • 9
  • 37
  • 79
0

I'd prefer neither because they are both too slow. Readability should not come at the cost of an exponential explosion in runtime, especially when there exists a simple way that runs in linear time.

I'd do this something like this (pseudo-code):

a = 0;
b = 1;
n.times { a, b = b, a + b; }

In C you'd have to use a temporary variable unfortunately, but the principle is the same.

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
0

I'd bet there's no difference in the compiled code. I'd at least try to make it a little more readable:

return n==0 ? 0 : ( n==1 ? 1 : fib(n-1) + fib(n+1) );
Earlz
  • 62,085
  • 98
  • 303
  • 499
Jay
  • 13,803
  • 4
  • 42
  • 69
0

I prefer the second one in most situations, but there are times where it seems a bit of a waste to not do it in one line. For instance, I'd prefer

text="my stuff_"+id==null ? "default" : id;

to

text="my stuff_";
if(id==null){
  text+="default";
}else{
  text+=id;
}

Note, this also helps with DRY because now if you need to change the name of text then you only change it in one place, compared to 3.

Earlz
  • 62,085
  • 98
  • 303
  • 499
0

if you use the ?: operator two or three times you will get used to it so i would go with the first

Hannoun Yassir
  • 20,583
  • 23
  • 77
  • 112
0

I'd say even more than @Lauri:

if (n == 0) {
    tmp = 0;
}
else if (n == 1) {
    tmp = 1;
}
else {
    tmp = fib(n-1) + fib(n-2);
}
return tmp;

It's good to have just one exit point.

fortran
  • 74,053
  • 25
  • 135
  • 175
  • So you'd prefer to use a temporary variable than having 3 points of return all at the end of a function and all in one place? – Earlz Feb 16 '10 at 17:58
  • What's the problem with that? The compiler should be able to optimise that without problems and it helps to write maintainable and debuggable code. – fortran Feb 16 '10 at 18:37
  • Introducing a temporary variable strictly for the purpose of restricting yourself to having only one exit point is the opposite of "maintainable" coding. – mocj Feb 16 '10 at 20:16
  • yeah, I bet you're a lot smarter than Dijkstra was... – fortran Feb 16 '10 at 20:23
  • When did I make such a claim? You can't seriously claim this version is somehow more maintainable than Lauris can you? – mocj Feb 16 '10 at 21:37
  • I claim that you don't know what extrapolation is. – fortran Feb 17 '10 at 00:49
  • You can claim whatever you like about me, but I notice you still haven't provided any insight into why you believe your example is somehow more maintainable than Lauris. – mocj Feb 17 '10 at 04:46
  • Having just one exit point is also good programming style. I don't argue with that. But must not be the only rule to guide you. Sometimes you have to make compromises. In a way my example also has one exit point as all the return statements have been bundled together using if statements. – Lauri Feb 17 '10 at 08:15
  • For a small example like this is OK to have as many returns as you want. But in real life, functions tend to grow when requirements change, and at some point this becomes a necessity because you don't want to spend time trying to figure out why that line of code you just added isn't being executed, then to realise that the function returned many lines above in one conditional branch. That's why. – fortran Feb 17 '10 at 09:51
  • I guess we'll have to agree to disagree. 3 quick reasons why not to do it: 1. You're adding a new symbol to the function scope, which can easily be confused with other symbols that may have similar names (temp vs. tmp) 2. You can accidentally re-declare the symbol inside of an enclosed scope of the function, hiding the original. 3. It introduces unnecessary nesting and branching. – mocj Feb 17 '10 at 19:00
  • 1. Agree, the name should be `result` instead of `tmp`. 2. That is improbable, even if it happens, the effect is near to the cause, so it can be tracked in a narrower scope than the whole function. 3. False. Look above again. Where's the unnecessary nesting and branching? – fortran Feb 18 '10 at 08:49
  • #2 - It's not improbable, especially in 'real life' long and complicated functions, more so when the original author of the code is not the one who is maintaining it. My point is this - why write code that has the potential to cause problems, however improbable, when you don't have to. #3 - you're half right here - there is no unnecessary branching in your code, however your final tmp = fib(n-1)+fib(n-2) is required to be within the else, Lauri's isn't. In fact you can remove the elses entirely. if(n==0) return 0; if(n==1) return 1; return fib(n-1)+fib(n-2); – mocj Feb 18 '10 at 16:03
  • #2 How many variables have your functions? What kind of names do you choose for your variables? Because I've never created a new variable with the name of another in a narrower scope without noticing (if I'm going to effectively use the new variable in the same scope)... #3 Let the micro optimisations to the compiler. If you really think that removing the `else`s will improve the code (in performance or readability), I hope to never have to work with you... :-s – fortran Feb 18 '10 at 17:33
  • Me too - finally you've said something we can agree on... Look, all I'm saying is that programmers make mistakes. Every line of code written contains the potential for bugs, either now or in the future through changes - so don't add unnecessary code - bugs cannot exist in code that doesn't exist. So - how many variables? Only the ones necessary and no more. Names? good ones for the given context. I believe shorter and simpler code is more readable, maintainable and is easier to debug - but as I said earlier we'll have to agree to disagree. – mocj Feb 19 '10 at 17:28
0

As a generic rule, you should write readable code, which means code which is most readable by the people who will actually read it. Most of the time, this means "yourself, three weeks later". When you write code, the good question is then "will I be able to read and understand it again next month ?".

Apart from that, the first expression is buggy (it uses fib(n+1) instead of fib(n-2)) and both exhibit the exponential explosion which makes Fibonacci sequence a classical tool for teaching some important practical aspects of algorithmics.

Thomas Pornin
  • 72,986
  • 14
  • 147
  • 189