LWN.net Logo

Quotes of the week

Paraphrasing the Alien films: "Under water, nobody can read your email".
Linus Torvalds

Tonight’s mainline Linux kernel contains about 100,000 instances of the keyword “goto”. The most deeply nested use of goto that I could find is here, with a depth of 12. Unfortunately this function is kind of hideous. Here’s a much cleaner example with depth 10.

Here are the goto targets that appear more than 200 times:

out (23228 times)
error (4240 times)
err (4184 times)
fail (3250 times)
done (3179 times)
exit (1825 times)
bail (1539 times)
out_unlock (1219 times)
err_out (1165 times)
out_free (1053 times)
[...]

John Regehr

diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -93,7 +93,9 @@ includes updates for subsystem X.  Please apply."
 
 The maintainer will thank you if you write your patch description in a
 form which can be easily pulled into Linux's source code management
-system, git, as a "commit log".  See #15, below.
+system, git, as a "commit log".  See #15, below.  If the maintainer has
+to hand-edit your patch, you owe them the beverage of their choice the
+next time you see them.
Greg Kroah-Hartman

"a beverage".

Pilsener, please.

Andrew Morton
(Log in to post comments)

Quotes of the week

Posted Feb 7, 2013 12:54 UTC (Thu) by pr1268 (subscriber, #24648) [Link]

Tonight’s mainline Linux kernel contains about 100,000 instances of the keyword “goto”.

Edsger Dijkstra is probably rolling over in his grave by now. Sigh.

Quotes of the week

Posted Feb 7, 2013 13:08 UTC (Thu) by khim (subscriber, #9252) [Link]

The big question is: since when it became fashionable to use Google-found links related to the phrase torn out of context without ever reading the articles which are pointed to by links?

Note that the link you've shown includes the following sentence: I do not claim that the clauses mentioned are exhaustive in the sense that they will satisfy all needs; but whatever clauses are suggested (e.g. abortion clauses) they should satisfy the requirement that a programmer independent coordinate system can be maintained to describe the process in a helpful and manageable way.

Not only Dijkstra notices that some additional clauses can be needed to write better programs (besides the usual if and while) - he offers one example where they may be needed (e.g. abortion clauses)!

C does not have such abortion clauses and they are emulated in kernel code with a goto statements, so... what's your problem?

P.S. I really, really hate anti-goto fanatics who entirely forget about the reason behind the infamous Go To Statement Considered Harmful article and start mindless crusade against goto without ever trying to understand just why Dijkstra felt that unbridled use of the go to is problematic and what he tried to achieve by trying to reduce it's use.

Quotes of the week

Posted Feb 7, 2013 15:33 UTC (Thu) by pr1268 (subscriber, #24648) [Link]

Don't blow a gasket! I was bordering on facetiousness with my earlier comment. Yes, I've read EWD 215; yes, I'm well aware of the fact that goto in kernel source code is for (what he refers to as) abortion clauses; and most definitely, yes, I'm also aware that those developing the kernel are among the most skilled and judicious programmers around. Also, I know that John Regehr's article mentions that goto "...has a number of legitimate uses in well-structured code".

If I personally have any criticism of goto, it's mostly that (1) it exists in nearly every programming language, and yet (2) academia is afraid of teaching it, perhaps out of fear it'll be misused by naïve programmers (as Dijkstra suggested). Another sigh...

In summary, I don't really have a problem with goto (at least how it's used in the kernel source), nor am I on a "mindless crusade" to end its use.

Quotes of the week

Posted Feb 8, 2013 3:07 UTC (Fri) by vonbrand (subscriber, #4458) [Link]

Before going off in just another anti-GOTO rant, read Knuth's classic "Structured programming with goto statements". There are very, very few absolutes. There are cases (like most of the uses in the kernel) where a goto makes for more readable, easier to debug, and moreover more efficient, code than any "structured alternatives".

Quotes of the week

Posted Feb 8, 2013 6:03 UTC (Fri) by dlang (✭ supporter ✭, #313) [Link]

The only absolute rule in computers is that for any rule you want to create that involves "you should NEVER do X", there will be some case, somewhere, where doing X is by far the best thing to do.

Quotes of the week

Posted Feb 8, 2013 14:23 UTC (Fri) by sorpigal (subscriber, #36106) [Link]

IMO absolute rules like that exist so that the under-informed don't cause too much damage. Well-informed people will just laugh at it and do whatever makes sense.

Quotes of the week

Posted Feb 11, 2013 20:48 UTC (Mon) by etienne (subscriber, #25256) [Link]

> IMO absolute rules like that exist so that the under-informed don't cause too much damage

That assumes the under-informed did not become your chief and did not install an automatic checker... you know, to produce quality code.
An amazing thing is the casing: hardware people use mixed case often finishing by n to tell the signal is inverted, firmware (Fpga) people often use all capitals but put a N before to tell the line is inverted, and the software quality rule is depending on which language part is used: uppercase if the line is described at the preprocessor level, lowercase if the same line is part of a structure its base address is defined by the linker. Yes, all of those names represent exactly the same bit.
Automatic software checker for best quality, anyway the only guy who want a single name is the initial author of the software, nobody else will ever read the hard/firmware docs (even if they should to fix a problem, instead of randomly adding one), so nobody will see the problem.

Quotes of the week

Posted Feb 9, 2013 1:34 UTC (Sat) by nevets (subscriber, #11875) [Link]

So what you are saying is...

"The only absolute rule in computers is that there are no absolute rules in computers"

Quotes of the week

Posted Feb 9, 2013 3:10 UTC (Sat) by dlang (✭ supporter ✭, #313) [Link]

pretty close :-)

Quotes of the week

Posted Feb 9, 2013 19:43 UTC (Sat) by nix (subscriber, #2304) [Link]

There is one rule that I can think of. "Your code has at least one bug you have not yet found."

(But that's more a 100% certain prediction than a dictate regarding how code must be written, so I guess it's not the same thing after all.)

Quotes of the week

Posted Feb 10, 2013 0:18 UTC (Sun) by dlang (✭ supporter ✭, #313) [Link]

well, you could get a trivial enough program that it doesn't have any bugs left, do I would say that has an exception ;-)

but as you say it's really more a prediction, I was talking about "thou shalt never use GOTO" type of rules

Quotes of the week

Posted Feb 11, 2013 17:58 UTC (Mon) by dgm (subscriber, #49227) [Link]

As the article where the quote comes from points, there are alternatives to the use of goto. I too was told to avoid using it, just to later rediscover that it was useful sometimes.

But what I wished to point out is that nesting if statements (the alternative pointed out by John Regehr) is not the only way to avoid using goto. Let me show you a couple of additional ones:

First we should make a canonical example of the accepted use of goto in kernel code:

int do_init()
{
  if (!init_step_1())
    goto out1;
  if (!init_step_2())
    goto out2;
  if (!init_step_3())
    goto out3;
  return 0;
out3:
  undo_step_2();
out2:
  undo_step_1();
out1:
  return -1;
}

And the if-ladder alternative would be:

if (init_step_1()) 
  if (init_step_2())
    if (init_step_3())
      return 0;
    undo_step_2();
  undo_step_1();
return -1;     

This looks shorter, but remember we are talking about nesting 12 levels deep here.

Now, the first alternative would be to use a separate function to perform each step, like this:

int do_init()
{
  if (init_step_1())
    if (try_init_2())
      return 0;
    else
      undo_step_1();
  return -1;
}

int try_init_2()
{
  if (init_step_2())
    if (init_step_3())
      return 1;
    else
      undo_step_2();
  return 0;
}

In that scheme, each function takes responsibility for doing/undoing some step (except the last one). That keeps set-up and cleanup code close together, making it more readable. The downside is that the code is now a bit longer, pollute the namespace, use more stack and are a bit slower. All this, though can be solved by inlining the functions or using static.

And the final option is to use expression statements:

int do_init()
{
  return (init_step_1() &&
    (init_step_2() &&
    (init_step_3()
    || (undo_step_2(), 0))
    || (undo_step_1(), 0))) ? 0 : -1;
}

Isn't it pretty?

Quotes of the week

Posted Feb 11, 2013 18:02 UTC (Mon) by johill (subscriber, #25196) [Link]

I'm not entirely sure what you were trying to say, but I'd like to point out that in your second example the code ordering should, according to kernel style, be the other way around because "try_init_2" should be static. Then it becomes more difficult to read.

Either way, none of these are as readable as the goto version, imho.

Quotes of the week

Posted Feb 12, 2013 1:06 UTC (Tue) by mathstuf (subscriber, #69389) [Link]

The try_init_2 function should be above? Is there a rationale behind it?

I tend to forward declare static functions and define them at the bottom of the file. I try to make code files read from top to bottom with high-level at the top and if you want to see what (e.g.) custom_compare does internally, you can scroll to it. Typically, the algorithm *using* custom_compare is more important and shouldn't be buried between 20 static functions.

Quotes of the week

Posted Feb 12, 2013 9:16 UTC (Tue) by johill (subscriber, #25196) [Link]

I've really never wondered about a rationale, but typically static forward declarations seem to be frowned upon.

Quotes of the week

Posted Feb 11, 2013 19:28 UTC (Mon) by Cyberax (✭ supporter ✭, #52523) [Link]

>Isn't it pretty?
No, it isn't.

Add a couple of variable assignments there and your 'pretty' code becomes a horrific mess.

Quotes of the week

Posted Feb 12, 2013 9:28 UTC (Tue) by dgm (subscriber, #49227) [Link]

As I already suspected, you lack any sense of beauty. :-P

But it's true, it's a mess. I had to actually _test_ the code to be sure it was right. It's the epitome of clear code, and that's why this style is not used by anybody sane.

But the comment was supposed to be read as tongue-in-cheek, and it's an interesting capability of the C language, anyway.

Quotes of the week

Posted Feb 12, 2013 11:29 UTC (Tue) by mgedmin (subscriber, #34497) [Link]

Speaking of testing the code to make sure it works, I think you're missing some braces in the nested-ifs example.

Quotes of the week

Posted Feb 12, 2013 14:06 UTC (Tue) by Cyberax (✭ supporter ✭, #52523) [Link]

Your code reminds me strongly of foot binding in China ( http://en.wikipedia.org/wiki/Foot_binding ). It was performed to conform to some abstract and absolute 'standard' of 'beauty', without any actual regard for consequences.

For example, what if I want to do:
> int a=frob();
> if (a==bramble())
> do_c(a);
between init_step_2() and init_step_3()?

In 'goto-based' code it would be absolutely straightforward. In your code - not so much.

Quotes of the week

Posted Feb 12, 2013 17:28 UTC (Tue) by dgm (subscriber, #49227) [Link]

Not that I recommend writing code like that (see my reply above), but it's not that difficult. The trick is using the comma operator:

int do_init()
{
  int a;
  return (init_step_1() &&
    (init_step_2() &&
    (a=frob(),a==bramble()?do_c(a):(void)0,init_step_3()
    || (undo_step_2(), 0))
    || (undo_step_1(), 0))) ? 0 : -1;
}

The C language offers you plenty of rope indeed.

Quotes of the week

Posted Feb 13, 2013 21:54 UTC (Wed) by khim (subscriber, #9252) [Link]

Note that we are talking about kernel code which means that you can stuff
({ anything you want })
in there.

Quotes of the week

Posted Feb 14, 2013 17:51 UTC (Thu) by dgm (subscriber, #49227) [Link]

I'm afraid that I don't understand you.

If you mean that "({ anything you want })" wont work for user mode code, then you're wrong.

On the other hand, if you mean that it's dangerous because it's kernel code... well, you can put exactly the same code in a separate statement, by simply adding a semicolon at the end. How is it "({ anything you want })" more dangerous than "({ anything you want });"?

Quotes of the week

Posted Feb 14, 2013 21:31 UTC (Thu) by khim (subscriber, #9252) [Link]

If you mean that "({ anything you want })" wont work for user mode code, then you're wrong.

It may work, or it may fail. "User mode code" often needs to be compiled by different compilers under different OSes thus ({ … }) is frowned upon. Kernel code is not supposed to be compileable by anything except GCC and, indeed, there are already some constructs which use this (and other) extensions in kernel.

Quotes of the week

Posted Feb 15, 2013 10:36 UTC (Fri) by dgm (subscriber, #49227) [Link]

Oh, that. Yes, but that's as simple as making "{anything you want}" into a function (which is not a bad idea because it's probably a non-trivial loop or switch statement) and presto!, you don't need any gcc extensions.

Quotes of the week

Posted Feb 15, 2013 10:42 UTC (Fri) by mpr22 (subscriber, #60784) [Link]

Depends what you're doing. There are things for which your options are "function name proliferation", "GCC statement-expressions", or "move to C++".

Quotes of the week

Posted Feb 15, 2013 11:53 UTC (Fri) by hummassa (subscriber, #307) [Link]

I, for one, would choose door #3, because of a simple truth:

There is no C program that could not be written better (or, in the worst case, equally) as a C++ program...

Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds