Rob Pike's simple Include rule

N

Neil Cerutti

In Rob Pike's style guide he urges the following:

Simple rule: include files should never include include
files. If instead they state (in comments or implicitly)
what files they need to have included first, the problem of
deciding which files to include is pushed to the user
(programmer) but in a way that's easy to handle and that,
by construction, avoids multiple inclusions.

I was startled by this guideline, since it's not what I think of
as the usual practice, i.e., brute-force idempotency through
header guards in the headers.

I have three questions about this advice, for those who use a
similar style:

1. Is following this guideline facile or hassle? I converted a
simple two-header program over to this style, making several
errors along the way. I clearly don't have experience
with it.

2. How does a header state implicitly what it requires for
headers? I assume he means that you gleen this information by
reading the header file, but I want to make sure I'm not missing
something interesting.

It seems like a good candidate for automation.
 
S

Sam Dennis

Neil said:
Simple rule: include files should never include include
files.

Is following this guideline facile or hassle?

Definitely a hassle, and the only real gain is to avoid polluting the
namespace; the quoted benefit (prevention of multiple inclusion) does
not matter one whit, as you can accomplish it with some pre-processor
directives, as you note.

For the real problem (namespace pollution), one should document which
headers are included by each.
 
A

Alan Balmer

In Rob Pike's style guide he urges the following:

Simple rule: include files should never include include
files. If instead they state (in comments or implicitly)
what files they need to have included first, the problem of
deciding which files to include is pushed to the user
(programmer) but in a way that's easy to handle and that,
by construction, avoids multiple inclusions.

I was startled by this guideline, since it's not what I think of
as the usual practice, i.e., brute-force idempotency through
header guards in the headers.

FWIW, I disagree with Rob Pike on this issue. I believe an include
file should include whatever other headers it itself needs. However,
it shouldn't include any others. Finding after the first compile that
some header file needed another header included in front of it is
legitimate grounds for cursing the author.
I have three questions about this advice, for those who use a
similar style:

1. Is following this guideline facile or hassle? I converted a
simple two-header program over to this style, making several
errors along the way. I clearly don't have experience
with it.

2. How does a header state implicitly what it requires for
headers? I assume he means that you gleen this information by
reading the header file, but I want to make sure I'm not missing
something interesting.

It seems like a good candidate for automation.

What's the third question? :)
 
S

Stephen Sprunk

Neil Cerutti said:
In Rob Pike's style guide he urges the following:

Simple rule: include files should never include include
files. If instead they state (in comments or implicitly)
what files they need to have included first, the problem of
deciding which files to include is pushed to the user
(programmer) but in a way that's easy to handle and that,
by construction, avoids multiple inclusions.

I was startled by this guideline, since it's not what I think of
as the usual practice, i.e., brute-force idempotency through
header guards in the headers.

Header guards are cheap and don't require extra vigilance on the part of the
programmer using your library. I've worked on a couple open-source projects
where include dependencies were a nightmare until I added header guards to
all the files and just brute-force included things in headers as needed.

What are the counter-cases where header guards are NOT the most efficient
solution?

S
 
T

Thomas Matthews

Neil said:
In Rob Pike's style guide he urges the following:

Simple rule: include files should never include include
files. If instead they state (in comments or implicitly)
what files they need to have included first, the problem of
deciding which files to include is pushed to the user
(programmer) but in a way that's easy to handle and that,
by construction, avoids multiple inclusions.

I was startled by this guideline, since it's not what I think of
as the usual practice, i.e., brute-force idempotency through
header guards in the headers.

In our shop we have the types
UINT8, UINT16, UINT32
defined a unsigned integers with the given bitwidth.

We have one file, let's say types.h, which defines those types
for various platforms.

So if I write a function:
UINT8 Public_Function(UINT16 variable)
{
/* ... */
}

and I want to make it public, I put it into a header file
my_functions.h:
UINT8 Public_Function(UINT16 variable);

Now, since it uses the UINT8 and UINT16 in the declaration,
those identifiers must be resolved before this function
declaration.

According to the style guide, a programmer must include
the types.h file before the my_functions.h file.

If the my_functions.h file has the statements:
#ifndef UINT8
#include "types.h"
#endif
before the function declaration, the user only has to
worry about including one function. The header file
takes care of its own declaration issues.


--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book
 
A

Alan Balmer

According to the style guide, a programmer must include
the types.h file before the my_functions.h file.

If the my_functions.h file has the statements:
#ifndef UINT8
#include "types.h"
#endif
before the function declaration, the user only has to
worry about including one function. The header file
takes care of its own declaration issues.

Exactly. But you say this is contrary to your style guide?

Better yet, imo, if the types.h file had a header guard, the
#ifndef/#endif in my_functions.h would be unnecessary.
 
N

Nick Landsberg

Alan said:
FWIW, I disagree with Rob Pike on this issue. I believe an include
file should include whatever other headers it itself needs. However,
it shouldn't include any others. Finding after the first compile that
some header file needed another header included in front of it is
legitimate grounds for cursing the author.



What's the third question? :)
Conjecture: The source of Pike's guideline may not
have been addressing C-language per se, but rather
external factors, such as the "make" program.
(Which makes this OT in c.l.c, I guess.)

The earliest versions of "make" only checked for
explicit dependencies as specified in the "makefile".

Thus, if a.c included a.h which included b.h *and*
b.h was not an explicit dependency in the makefile,
then a.c would not get recompiled when b.h changed.
At best, you got a compile-time error. At worst,
you got undefined behavior or a core-dump after
delivery to the customer.

Developers were usually good about finding all the
#include directives in their own code in order to
create the makefile, but hardly ever checked whether
or not there were nested includes within other files.
This /may/ have been the reason for the guidelines
noted above.

More modern versions of "make" do this checking
for you. So if you have those versions, it has been
automated already.
 
D

Dan Pop

In said:
In Rob Pike's style guide he urges the following:

Simple rule: include files should never include include
files. If instead they state (in comments or implicitly)
what files they need to have included first, the problem of
deciding which files to include is pushed to the user
(programmer) but in a way that's easy to handle and that,
by construction, avoids multiple inclusions.

I was startled by this guideline, since it's not what I think of
as the usual practice, i.e., brute-force idempotency through
header guards in the headers.

I have three questions about this advice, for those who use a
similar style:

1. Is following this guideline facile or hassle?

It's a nightmare for both the implementor and the user. Consider
things like size_t and NULL, that are supposed to be available in
several headers: if the implementor wants to change one of them, he
must take care to change *all* the headers defining/declaring the
identifier in question.
2. How does a header state implicitly what it requires for
headers?

If you see the following in a header:

void foo(FILE *);

then this header implicitly states that <stdio.h> must be included first.

I guess Pike was either drunken or stoned when he suggested that the
users of a header actually read the header in order to figure out its
dependencies.

Dan
 
C

Christian Bau

[email protected] (Dan Pop) said:
In <[email protected]> Neil Cerutti


It's a nightmare for both the implementor and the user. Consider
things like size_t and NULL, that are supposed to be available in
several headers: if the implementor wants to change one of them, he
must take care to change *all* the headers defining/declaring the
identifier in question.


If you see the following in a header:

void foo(FILE *);

then this header implicitly states that <stdio.h> must be included first.

I guess Pike was either drunken or stoned when he suggested that the
users of a header actually read the header in order to figure out its
dependencies.

I prefer the rule that

#include "header.h"

as the first line in a source should compile without error for every
header file, and that changing the order of "#include"s should not make
any difference.
 
E

E. Robert Tisdale

Christian said:
I prefer the rule that

#include "header.h"

as the first line in a source
should compile without error for every header file, and that
changing the order of "#include"s should not make any difference.

This is equivalent to saying that header files should be

1. self sufficient and
2. idempotent.
 
X

xarax

Nick Landsberg said:
/snip/

Conjecture: The source of Pike's guideline may not
have been addressing C-language per se, but rather
external factors, such as the "make" program.
(Which makes this OT in c.l.c, I guess.)

The earliest versions of "make" only checked for
explicit dependencies as specified in the "makefile".

Thus, if a.c included a.h which included b.h *and*
b.h was not an explicit dependency in the makefile,
then a.c would not get recompiled when b.h changed.
At best, you got a compile-time error. At worst,
you got undefined behavior or a core-dump after
delivery to the customer.

I would think that most developers using MAKE would
have added a dependency line specifying that a.h
depends on b.h, with a "touch" command that will
make a.h current (thus trigging a compile for a.c).
 
D

Dik T. Winter

> Conjecture: The source of Pike's guideline may not
> have been addressing C-language per se, but rather
> external factors, such as the "make" program.
> (Which makes this OT in c.l.c, I guess.)

I do not know from what time Pike's guideline comes, but I think it
is an old guideline, and indeed made sense with old versions of make
without additional tools.
> The earliest versions of "make" only checked for
> explicit dependencies as specified in the "makefile".
>
> Thus, if a.c included a.h which included b.h *and*
> b.h was not an explicit dependency in the makefile,
> then a.c would not get recompiled when b.h changed.
> At best, you got a compile-time error. At worst,
> you got undefined behavior or a core-dump after
> delivery to the customer.

That is why already quite early the command 'makedepend' was created
which would get all dependencies and add them to the makefile.
 
K

Keith Thompson

CBFalconer said:
I was that far off huh. Not too bad for a blind stab with no
furlong sparrows frolicing outside my window for the past
fortnight.

I see now that I didn't read your original question carefully enough.
You asked about sparrows, not swallows. Since sparrows are much
slower than swallows, you may have been pretty close. (27 kf/fn is
about 10 mph or 4.5 meters/second, which seems plausible for a
sparrow, though I don't have any actual figures.)
What about max. accelleration, in kf/fn^2?

Sorry, maximum acceleration of sparrows and swallows is off-topic.
 
N

Nick Landsberg

xarax said:
I would think that most developers using MAKE would
have added a dependency line specifying that a.h
depends on b.h, with a "touch" command that will
make a.h current (thus trigging a compile for a.c).

<OT>
"Most" does not include "all" by definition.

(Not being sarcastic, just realistic.) All it takes
is one developer who doesn't do it and the house of cards falls.

I have personally rapped the knuckles of those
who did not in the days when I was the "integrator".

Actually, it's easier to change the makefile to
have a dependency on both a.h and b.h rather than
use the "touch" command.
</OT>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top