
Notes on Programming in C - Rob Pike, February 21, 1989 - AbyCodes
http://doc.cat-v.org/bell_labs/pikestyle
======
avar
One thing I've changed about my style in the last few years is to almost never
comment my code, but to instead write long and detailed Git commit messages
explaining the how's and why of that code at the time that I write it.

That means that over time I effectively have comments for every line of code
in the program, but it's associated metadata instead of being embedded inline,
which means that the comments never go out of date, and their history is
accurately tracked in version control.

~~~
jberryman
That's sounds interesting. I'm a bit of a git newb; what git commands or tools
do you use to make this convenient?

~~~
electrum
IntelliJ IDEA or any of the JetBrains IDEs based on that platform (RubyMine,
WebStorm, etc.) have this built-in: right click in the gutter and choose
Annotate. Mouse over a line to see the commit message for the most recent
change to that line.
[http://www.jetbrains.com/mps/whatsnew/screenshots/20/annotat...](http://www.jetbrains.com/mps/whatsnew/screenshots/20/annotate.png)

------
jbellis
Many of these are elaborated on in the more recent (1999) "The Practice of
Programming." Excellent book. [http://www.amazon.com/Practice-Programming-
Brian-W-Kernighan...](http://www.amazon.com/Practice-Programming-Brian-W-
Kernighan/dp/020161586X)

------
nitrogen
The one point that is notably less relevant today is the last section
regarding include files. Gcc has a special case for a header file that is
entirely wrapped in an #ifndef
([http://gcc.gnu.org/onlinedocs/cpp/Once_002dOnly-
Headers.html...](http://gcc.gnu.org/onlinedocs/cpp/Once_002dOnly-
Headers.html#Once_002dOnly-Headers)).

~~~
apaprocki
The more modern gcc handling is with "#pragma once":

<http://en.wikipedia.org/wiki/Pragma_once>

His comments on include files are _not_ the way the world has gone. In all my
years writing C, I have never seen a C/C++ header which does not include the
other headers it needs in order to compile cleanly.

He states: "Simple rule: include files should never include include files."

If you can find me one C project out there which has headers with zero
#includes and forces each compilation unit including the header to include all
the prerequisites needed for that header I would be genuinely interested. Even
all OS header files include their pre-requisites and it is considered a bug if
they do not do so. A more modern 21st century rule would be:

"Simple rule: include file order does not matter. Use include guards (or
#pragma once) and always include only the prerequisites needed to cleanly
compile and nothing more."

~~~
keithflower
Our experiences don't match. Avoiding nested includes has been a part of the
rigorous and useful standards of a lot of important, mission-critical, large-
scale projects, and is something I try to enforce in my own code.

There are numerous examples of projects which follow that recommendation. I'm
told, for example, that the recommendation on the excellent Blender 3-D
graphics system is to avoid nested includes. Other examples:

NASA: <http://sunland.gsfc.nasa.gov/info/cstyle.html>

European Molecular Biology Open Software Suite (EMBOSS)
[http://emboss.sourceforge.net/developers/c-standards_new.htm...](http://emboss.sourceforge.net/developers/c-standards_new.html)

Atacama Large Millimeter Array (astronomy):
[http://www.alma.nrao.edu/development/computing/docs/joint/00...](http://www.alma.nrao.edu/development/computing/docs/joint/0009/2001-02-28.pdf)

Clinical Neutron Therapy System (for radiation oncology):
<http://staff.washington.edu/jon/cnts/impl.pdf>

~~~
tptacek
I take your point, but I'm not sure you're really taking his. As another data
point, I just did a find/xargs-grep across my "~/codebase/3p" tree, which has
~5500 .h files for projects ranging from MongoDB to Ruby and Python to OpenSSL
to valgrind. Virtually all of them have nested includes. Many of them are
components of mission-critical software.

He's right; nested includes are a modern C idiom.

~~~
keithflower
> In all my years writing C, I have never seen a C/C++ header which does not
> include the other headers it needs in order to compile cleanly.

> He's right; nested includes are a modern C idiom.

No doubt they are found a lot. The request was for counterexamples.
Fashion/style vs engineering practice assertions may be passing like ships on
a nighttime C here.

>...for projects ranging from MongoDB to Ruby and Python...

Python....why, even Tim Peters asserts that "Flat is better than
nested"...wink...

<http://www.python.org/dev/peps/pep-0020/>

/irrelevant quote

------
zmj
These style guidelines correspond exactly to idiomatic Go. I'm impressed how
well Pike executed on his philosophy.

------
theorique
_Pointers are sharp tools, and like any such tool, used well they can be
delightfully productive, but used badly they can do great damage_

Nice physical metaphor. Pointers are ... pointy.

------
huskyr
Even though this is over 20 years old, many comments are still very valid. I
especially like the section about short variable names and functions.

~~~
dextorious
I can see how loop indexes (i) etc are nice to be short, but I don't see how
the other stuff is valid, as opposed to a personal preference.

Why is maxval a better name than MaximumValueUntilOverflow?

The first lacks some extra information that I need to keep in mind every time
I re-read that part of the code.

And while the potential of overflow might be obvious, how about:

minValueForTemperature instead of minval?

~~~
adbge
My variables are a little more verbose than the anemic style preferred by Rob
Pike and used throughout K&R but, in that tradition, I also tend towards
shorter, simpler variable names than something like minValueForTemperature, so
maybe it would be useful to illuminate my own thinking.

Complex variable names ought to be avoided because, simply, they _hammer_ the
programmer with a bunch of information every time they are used. Usually, when
reading code, you're trying to wrap your head around how a procedure operates
rather than the specifics of what it's operating on. Often, if you need to
know more about what a variable represents, it's sufficient to refer to its
declaration.

Thusly, I prefer to name my variables so that one can pick up the general idea
of what they're for from the name and then I document any additional
information at the variable's declaration, either using a comment or via the
type system.

So, this is how I'd handle your examples:

    
    
        int maxval; /* until overflow */
        Temperature minval;

------
halayli
Those notes found their way to 'The Practice of Programming' book.

I highly recommend it.

------
falcolas
Some absolutely fascinating points. However, I must admit that the portion on
link pointers was, frankly, damned frightening as someone who could possibly
have to come back and figure out what's really going on.

I'm reminded of Perl when I look at that link pointer code. It's succinct,
easy to write, works great most of the time, and nearly impossible to go back
and decode later. You simply require too much context to find the one place
where you stepped beyond the array and into no-man's land.

I love pointers; I think that like other sharp tools, they have their uses.
However, like other sharp tools, they require training and attention to use
properly. Lots of people lose fingers to saws every year; how many brain cells
have you lost to debugging pointer mistakes?

~~~
tptacek
That's idiomatic C code. You're right that it's not particularly readable if
you aren't a C programmer, but if you came to a job interview and couldn't
grok it immediately, I'd write "facility with C: marginal" in my notes.

~~~
falcolas
Missed this back closer to when you posted it - but it's less that I don't
understand what's going on, and more that this code is more likely to go wrong
& be harder to debug than more descriptive code.

Just the other day, I was trying to identify what was being done by someone's
"idiomatic" code, and had to keep three vertical screen's worth of data up
just to follow what was happening. All that code was wrong, but because they
were using pointers "idiomatically", it took a long time to find their off-by-
one error.

Granted, they had gone about 4 levels further with pointers than the given
example in the article, but the premise is similar.

