Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Per the Linux kernel coding style document:

The answer to that is that if you need more than 3 levels of indentation, you're screwed anyway, and should fix your program.

What can I deduce from this quote? On top of the fact that too long methods are hard to maintain, are they hard or impossible to optimize for the compiler?

I don't really understand if this quote encourages better coding practice or is really a mathematical / algorithmic sort of truth.

I also read in some C++ optimizing guide that "dividing up a program into more functions improves its design" is frequently taught in CS courses, but it should be not done too much, since it can turn into a lot of JMP calls (even if the compiler can inline some methods by itself).

share

migration rejected from stackoverflow.com Apr 30 at 9:16

This question came from our site for professional and enthusiast programmers. Votes, comments, and answers are locked due to the question being closed here, but it may be eligible for editing and reopening on the site where it originated.

closed as primarily opinion-based by gnat, MichaelT, amon, Martijn Pieters, ChrisF Apr 30 at 9:15

Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise.If this question can be reworded to fit the rules in the help center, please edit the question.

20  
I'd deduce that the person who said it is over-generalizing, and should be challenged to say something worthwhile about whatever particular case it is they're actually talking about, not about some invented rule that all programs with 4 levels of indentation are "broken". –  Steve Jessop Feb 27 '11 at 18:35
11  
@Steve Jessop: the person who said it is Linus Torvalds, in the Linux kernel coding guidelines. Torvalds is not known for his subtlety. –  larsmans Feb 27 '11 at 20:04
12  
@larsman, Jens: He's not the only one who can be unsubtle. OK, fine, he has his tab set to 8 spaces (because he personally has difficulty reading code with 4), on an 80-wide terminal. He needs some high-falutin' argument to dismiss a perfectly reasonable issue raised about the consequences of his settings. I'm willing to follow accessibility guidelines where necessary, so if I was contributing to the kernel there would be no need to fob me off with specious nonsense. But fortunately for me, Linus doesn't need to read my code, so I don't have to follow his rules or care why he invented them ;-p –  Steve Jessop Feb 27 '11 at 22:06
8  
@Matthieu: Indeed, and they might indent differently when subject to the rule than when not. Goodhart's Law suggests that if anyone did impose a rule as blunt as "no more than three levels of indentation", they would soon have to invent a lot of subsidiary rules to stop people spuriously "optimizing" their code for indentation without actually improving it. For instance you might see more gratuitous use of lines like while (*dst++ = *src++);, since it "cheats" by using one less level of indentation than a two-liner. And no doubt far worse abuses that will be invented. –  Steve Jessop Feb 27 '11 at 22:19
3  
@Jens, @Steve: I know the context of the question - Torvalds manages an effort to maintain a particularly critical piece of code by employing infinite numbers of monkeys banging away at their keyboards. He has to set a limit and I suspect some of the most experienced kernel developers can get away with four indents every now and then. –  larsmans Feb 28 '11 at 6:23
show 9 more comments

14 Answers 14

up vote 70 down vote accepted

What it means to say is that as you add more indents to your code, you add more nested logic and your code gets harder to understand. It's more about being able to maintain rather than compile, process, or perform optimally.

For instance:

for(int i=0; i<10; ++i){
    Object val = repeat(i, someVar);
    if(val.value > 3){
        switch(val.item){
        case DOG:
            if(mProcess){
                outputToUser(val);
                doMoreThings(val, mMoreThingDoer);
                if(mRepurpose){
                    addExample(val);
                }
                // and so on, and so on...

It's just very hard to reason and remember all the variables that might go into the different indentations. Which one is in which scope? Where is it being reassigned? How many things can you keep in your head?

On the second part of the question, regarding the additional function calls, don't avoid them. That's premature optimization. First, design your code so that it can be maintained. Then benchmark. Then worry about performance. If you're in the realm where you're having to worry about function call overhead, you're probably also in the realm where you need to reevaluate all data structures and algorithms used.

share
1  
ladder programming –  aaa Feb 27 '11 at 18:01
5  
This uses 5 levels of indentation, 6 given that it presumably appears inside a function body. So it doesn't demonstrate that 4 is too many. –  Steve Jessop Feb 27 '11 at 18:40
5  
@Steve Jessop: That's an argument anyone who hasn't been on maintenance or haven't written any unit-tests would make. 4, 5, or 6 indentation levels doesn't matter. If you need to indent, why not make it more modularized by adding a function instead? It's not that much more work. –  Spoike Mar 10 '11 at 8:27
14  
@Spoike: While I'm the first to argue pro factoring out code into their own function (and, different from Linus, who despises C++, C++ programmers have inlining to not to make this a performance issue) wheaties' certainly is a ridiculous example that only shows what we all knew: you can have too much of indentation. But it's just trivial to come up with an example of four level of indentation that is easy to read according to most. Not surprisingly, the morale, as always, is: There's no hard number as a limit, you will have to employ common sense and pity for those who come after you. –  sbi Mar 10 '11 at 11:08
    
I can see that indiscrimant object and variable declarations at different nesting levels make the code that mch more difficult to read. However, just because something is available doesn't free the programmer from the responsibility of writing readable code and therefore doesn't require him to use it just because it's there. If more readable code requires declarations to be bunched together and not spread all over the place then what's the problem with that? C programmers may write super-tricky code yet at least 99% of them do not because they realize that it hurts readability. –  Olof Forshell Mar 12 '11 at 20:10
show 2 more comments

Humans generally can maintain 7 +- 2 "things" in their short term memory. Too many levels of indent and a generic human programmer can no longer read the code and maintain the entire context of all the conditions for a particular block of code in their short term memory. It's even worse than that, since some humans may think since they just read the last N nested block conditions, they actually remember them all. This is a recipe for creating bugs.

e.g. a human brain "stack overflow".

The alternative is to reread and reread until longer term memory kicks in and helps or the brain starts to recognize and chunks several "things" into fewer larger "things". This can slow a programmer down by a ratio well above the number of lines of code or indent blocks.

Compilers don't have this same problem, they're fine memorizing this stuff to the limits of ECC swap memory. So it's not an algorithmic problem.

share
1  
Of course psychologists are pretty vague and subjective about what is meant by "one thing". If we interpret it as meaning one word, we'll have big problems. Thankfully, we can just forget the whole issue by considering "one thing" to refer to "one source file" or "one project", and fall back on common sense without upsetting the psychologists sensitivities too much. After all, "once glance" contains a huge amount of graphical information and cognitive psychologists have studied the way we can process significant chunks of text at a glance, so we already know it's not "one trivial thing". –  Steve314 Feb 28 '11 at 5:15
3  
@Steve314: I've read the original "7 things" paper and I assure you the lack of definition for "thing" bothered its author as well. However, if you'd imagine a human brain as a CPU with 7 registers, it makes some sense: when handling a project, they point to files; when writing a module, to functions; when writing a function, to variables. –  larsmans Feb 28 '11 at 6:28
    
@larsmans - OK, but the context here is indented block structures. The whole point of indentation is to make the nesting of block structures a visual at-a-glance thing. The overall structure of a quite complex function (so long as you can see it all at once) is substantially one at-a-glance thing. The details aren't, but moving those details into the call graph won't eliminate any complexity. By splitting out those details into multiple functions, one possible result is that things that would have been perceived as one at-a-glance thing must now be perceived separately. –  Steve314 Feb 28 '11 at 6:45
    
@Steve314: in the cited coding guidelines, Torvalds takes on the question "but what if my 8-tab indents make the code move too far to the right?" I think what he's saying is: your code is too complex to start with. Many levels of indentation probably mean too high cyclomatic complexity for a single function and often too many variables. –  larsmans Feb 28 '11 at 6:50
    
@larsmans - BTW - +1 that infinite monkeys comment. Maybe we're not thinking so differently after all. –  Steve314 Feb 28 '11 at 7:07
show 3 more comments

Not having more than three levels indentation is by no means a rule. Sometimes it's unavoidable. You're right in that the quote is trying to encourage better coding practices. Generally a method should perform a single function. Sometimes when you see more than a few levels of indentation your method is performing multiple functions, and it might be better to break it up, even if your method isn't being reused elsewhere.

share
5  
I don't think it is ever *un*avoidable. You should be able to break apart nested logic into separate functions, taking advantage of the fact that they will reset the indent count for the code inside them. –  erisco Feb 27 '11 at 18:34
2  
@erisco - A volume field with a time variable = 4 dimensions. Sometimes it is unavoidaable (most tensor calculus) –  Rook Feb 27 '11 at 23:22
    
@erisco: I was definitely thinking math and AI algorithms when I said "unavoidable," though my AI book is at the office otherwise I would have given an example. –  Cory Larson Feb 27 '11 at 23:46
    
I've written a vast amount of embedded code where 4, 5, 6 levels of indentation are normal. A function might only be 20-50 lines and do a well defined task but by the time you have a couple of conditions, a loop, and a test inside you can be up > 3 levels withou trying. Using 3 or less levels just makes it less clear, bigger, harder to understand and maintain. Like most rules, this one is "do this when you can because its a Good Thing. (Oh and when it does not make sense then do something that does.)" –  quickly_now Mar 10 '11 at 8:03
add comment

Go tell that to the HTML boys.

With 3 levels of nesting of <div>'s you don't even get past the basics of a page:

<html>
  <body>
    <div>Here goes your last level of nesting. Have fun today.</div>
  </body>
</html>

The same goes of a source file of an object-oriented programming language with namespaces:

namespace MyProgram
{
  class MyClass
  {
    void MyMethod
    {
      // Throw it all here - more nesting is not allowed... :(
    }
  }
}

P.S. Hasn't it been enough lately of idiotic quotations from clueless "professors"?

share
18  
HTML isn't a programming language, it's a markup language, and is irrelevant to the question for many reasons including the lack of program logic, which is what Torvalds was talking about. On the second example, since he was speaking of C functions, the count would start at the function/method level. Whether he was right or wrong, he definitely wasn't talking about either of your examples, and he's certainly not a "clueless 'professor'". –  Matthew Frederick Feb 28 '11 at 1:43
1  
3 levels quote is a Torvalds 'classic', as with all his various musings, take it with a pinch of salt, I'm pretty sure he does. Crazy Eddie's answer is the truth. –  Slomojo Feb 28 '11 at 6:34
    
Note that this rule would make getters and setters in C# -- a very useful feature -- completely unusable, as they'd be nested four layers deep (Namespace -> Type -> Property -> Getter/Setter) for the most basic code. –  MiffTheFox Mar 10 '11 at 10:18
4  
Linus Torvalds isn't a professor. He's a highly successful and eminent kernel programmer with a strong propensity to shoot his mouth off and overgeneralize like crazy. His statements are usually worth reading (there's usually some truth to them), but should not be taken as gospel. –  David Thornley Mar 10 '11 at 15:14
    
declarative langauges like HTML do not require the human reader to remember variable values. There's no algorithm to trace. deep nesting of an imperative algorithm with lexical scope has more values to remember at once to correctly trace the algorithm in your mind. –  mike30 Nov 7 '12 at 22:13
add comment

One of the side effects of the "obfuscated C" thing is that some people go too far the other way, damaging the readability of their code as a result.

Refactoring into functions (ie breaking the code into separate chunks) can easily hide structure that helps with readability. Moving complexity into the call graph doesn't eliminate that complexity, so the important thing is whether the high level stuff still makes immediate sense when you're seeing the names of the low level stuff, not the implementation. "Immediate sense" can include all kinds of details - is the upper bound n, or n+1, or n-1 etc etc.

If there's a sensible function name that explains what the function does, so you're compositing abstractions, and so that it's obvious when the parameters are correct, that's good.

If you're refactoring due to a nesting count or a line count - purely because of an inflexible style rule and ignoring actual readability - I don't want to maintain your code.

The problem with judging readability is that you know what the code is intended to do as you write it. It's not the same as understanding something someone else wrote, or coming back to your own code 5 years later. There's a lot of rules and guidelines intended to counter that. Some are important, but some go too far.

My view - over time, you'll learn by experience what is genuinely readable. Don't disregard the common style rules, but don't obsess over the thousand-page style guides either. There's lots of good advice out there, even in those thousand-page style guide books, but you can't write code at all without breaking someones pet style rule.

Of course if your employer requires that you follow certain rules, you follow them - or if you really can't, find another employer.

share
add comment

It's just a statement to encourage you to write readable code.

As to your C++ optimization guide...

Write your code to be readable first. Then if you really need to optimize some areas (and you've determined this by measuring with a profiler), go ahead and cut/copy/paste code from the function directly at the call site.

share
add comment

In C# I would not want to limit myself to 3 levels per file:

namespace XYZ
{
    public class MyClass
    {
       public string SomeMethod()
       {
          if (SomeCondition())
          {
             // now I'm at 4 levels :-(
          }
       }
    }
}

But maybe more than 3 levels per method should warrant an investigation.

share
4  
Perhaps the quote is indirectly saying the C# programmers are screwed ;-) –  Skizz Mar 16 '11 at 11:57
add comment

There is an issue of complexity vs locality. By spreading your code over multiple fuctions to reducing comlexity, you spread out the algorithm. In some cases this is good, you get to isolate and name a part of the algorithm. There are cases, however, where keeping everything tight is clearer:

for each planet in solar system for each country in planet for each city in country for each suburb in city for each house in suburb if house.hasCat house.explode()

share
add comment

There are three parts to the "three levels of indentation" think that I think need to be addressed.

The first point has already been mentioned, but keep in mind that this is referring to C, so it's not as though you are going to start out a by writing code in a function that's inside a class that's inside a namespace or anything.

Second, keep in mind that Torvalds was talking about the coding standard for the kernel. Kernel space is different than userspace, and in some ways much simpler. You don't want your kernel module to be thinking too much- if it needs to do more than provide some basic bit of functionality the higher level logic should almost certainly go into a userspace library anyway.

Finally, I don't believe that he was advocating simply taking the inner levels of a function and arbitrarily moving them into a function (or maybe he was, but I wouldn't recommend it). Too many levels of indentation is often a sign of what I call "brute-force logic". Most of the time re-thinking the logic of the program can allow you to greatly simplify it without having to simply move the nested bits into their own functions.

share
add comment

If you look at the context of the quote another matter being discussed is TAB positions and their being hard (i e 0x09 TAB character) fixed at eight columns and that that is what they should be - not spaces and not two or four or something else but eight columns. They also speak of eighty column displays. Put that together and OF COURSE you're screwed with more than three indentations!

I'm a somewhat grudging fan of Windows NT and one reason is its graphical UI and that you can attach the most monstrous displays to it and THEY WORK! I remember a job in 2006 where I couldn't get a normal frigging (excuse me) 1280 display to work with Debian because there were no drivers and no clear guidelines how to tailor working settings and no test mode to test settings without having to reboot in case they were incorrect.

Let the Linux people continue programming max-three indentation functions in text mode editors on 80x24 screens and using hard, eight column TABs if that is what makes their day. To me the statement is out of date and without bearing to speak of (except perhaps in the Linux world) so I say lock it up inside the Linux walls and let us less restricted (at least screen-wise) be on our way with more useful programming guidelines.

On the statement itself (out of context) I personally feel that writing a multitude of short functions that call each other is over-rated when it comes to readability. I've seen functions that are indented to ten levels or more that aren't difficult to follow at all so to me it's 1. a question of judgement and 2. a question of formatting.

When it comes to (at least) C there is a coding style that places the opening brace on the same line as its condition/else and places the closing brace on a line of its own. This produces more compact but (to me) less readable code. I suspect that someone once wanted to fit more code into his/her (text mode?) editor display and found that his was a way to do it. Someone else saw the code and thought "that looks cool" and got the ball rolling.

I've always given braces and elses lines of their own with the same indentation as the original if/while/for. Those extra lines (quite few actually) do a great deal to bunch together related sequences which at least is one method I use to get a grip on code. Aligning comparison operators, logical operators assignments etc is another means I use.

There are types of code where coding style guidelines are actually detrimental to readability. But there will usually be a guideline policeman there to tell you that no one is above the law (even if guidelines for the most part are strongly suggested, but not actually mandatory).

share
    
The X11 display system and the Linux kernel are different projects with different people and different rules. Commenting about them as if they were one thing shows ignorance. –  Mikel Mar 10 '11 at 10:44
2  
@Mikel: So what if they are different teams? It still doesn't work. I once paired with a Gentoo aficionado to get a standard off-the-shelf Logitech webcam working on his machine for some capturing project. Took us two fucking days! Just for kicks, I (who had never ever held a webcam in my hands before, let alone tried to use it), plugged it into my WinXP laptop. I had it working within 5mins. And as a user, I don't really care why it doesn't work, but I do care if it steals the team 4 man days. –  sbi Mar 10 '11 at 11:17
    
@sbi I'm not agreeing or disagreeing, I'm just saying Linus's 3 tabs rule cannot be the cause of the display issues you experienced. –  Mikel Mar 10 '11 at 11:40
    
@Olof Forshell You might have seen readable functions nested ten levels deep, but I have not. Every function I've seen that goes more than even four levels quickly devolves into a morass of case or if/else if statements. Also, you're ignoring the fact that having functions allows the IDE to help you. If you don't factor your code into functions, you're forgoing that help. –  quanticle Mar 10 '11 at 14:18
    
@sbi: At home, the incompatibilities I have are generally Windows-related. I haven't managed to get a Windows machine to print to my networked printer, but the Macs and Linux boxes have no problem whatsoever. Last time I installed a dual boot on a laptop, I had serious driver issues with Windows 7 and minor config issues with Ubuntu 10.04. That's my anecdotal data, anyway. –  David Thornley Mar 10 '11 at 15:17
show 3 more comments

Don't bother with what the compiler will do. Sometimes, you break your code into small pieces and it reassembles everything in a big function. Sometimes it breaks by himself a function into smaller pieces and does a lot of JMP.

The coding rules rarely target compiler stuffs, but exists in most case to help the understanding and maintenance of the source code.

share
add comment

If you have more than 3 nested levels in your code I wouldnt say you're screwed, but it is an indicator of a possible problem with the algorithm. Plus, when code starts getting that nested, its very easy to introduce maintainability issues.

share
add comment

@hotpaw2: Re "Humans generally can maintain 7 +- 2 "things" in their short term memory." (can't comment directly, so I'll post an answer, sorry about that).

This rule is about 7 unrelated things; If the things are related in some way you can remember more than 7.

Anyway, I'm not sure you can identify levels of indentation as separate contexts. In procedural/imperative programming style, you'll have quite some 'sibling levels', which might have different contexts. Often, it are these sibling contexts that make it harder for me to understand a function.

To me, the 'skyline' of the indentation is an indication of complexity/sloppiness:

xxx
  xxx
    xxx
  xxx
  xxx
    xxx
xxx
  xxx
    xxx

Is probably worse than

xxx
  xxx
    xxx
      xxx
        xxx

My 2 cents...

share
1  
The first part of your answer should be given as a comment to the answer you refer to. –  user281377 Mar 10 '11 at 21:07
    
Indeed, but I don't have the privileges yet to do so. –  Peter Frings Mar 15 '11 at 20:43
add comment

Number of indentation affects program complexity, readability, number of executions paths through routine, number of bugs etc.

This is described nicely in Beautiful Code in chapter Code in Motion.

Also you can read pretty the same in Overcome Indentation section of Seven Pillars of Pretty Code.

share
add comment

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