Style guides for C and/or C++

V

Vicent Giner-Bosch

I've been searching at this forum and at the Internet for style guides
for C and/or C++, and I've found this one:

http://www.psgd.org/paul/docs/cstyle/cstyle.htm

Also, I've read some threads about C style matters. I think there is
really a lot of stuff!

I just would like to ask you for a quick answer to this question:
which style guide or style rules do you recommend me to use when
writing C code? It would be great if many of you would answer, so we
all could have here a thread with a good summary about this subject.

Thank you for the feed-back!! :)
 
T

Tom St Denis

I've been searching at this forum and at the Internet for style guides
for C and/or C++, and I've found this one:

http://www.psgd.org/paul/docs/cstyle/cstyle.htm

Also, I've read some threads about C style matters. I think there is
really a lot of stuff!

I just would like to ask you for a quick answer to this question:
which style guide or style rules do you recommend me to use when
writing C code? It would be great if many of you would answer, so we
all could have here a thread with a good summary about this subject.

Thank you for the feed-back!!    :)

I think you'll find there is some common ground but everyone kinda has
their own styles.

Above all, write maintainable code. To that end there are some common
sense things you can do to improve those odds

- write sensible comments. That doesn't mean comment every C
statement, but where it's useful to know what's going on
- use sensible variable names that are not overly short or long
- Try to keep the per file lines of code low when possible refactor
code to make the most re-use per line as possible
- Be consistent in your application of style and naming conventions
- Design software in a reducible manner [goes with refactoring]. That
is always try to reduce the correctness of a new function to the
assumption that functions it calls are correct.

etc...

As for the very specifics ... everyone differs. For instance, I
prefer using the declarations, initializations, code block style.
Others have rightly defended their own choices. There is no "right"
or wrong, just be consistent and thorough.

Above all, don't go around blindly applying other guidelines like
MISRA just for the fun of it, you'll likely miss REAL bugs in your
software while you spend time adhering to some random set of rules...

Tom
 
J

John Bode

I've been searching at this forum and at the Internet for style guides
for C and/or C++, and I've found this one:

http://www.psgd.org/paul/docs/cstyle/cstyle.htm

Also, I've read some threads about C style matters. I think there is
really a lot of stuff!

I just would like to ask you for a quick answer to this question:
which style guide or style rules do you recommend me to use when
writing C code? It would be great if many of you would answer, so we
all could have here a thread with a good summary about this subject.

Thank you for the feed-back!!    :)

If you're working on a larger team (and you're not in a position of
influence over this kind of stuff), adopt the convention used by the
rest of the team, even if you hate it.

If you're coding for yourself, it doesn't really matter, as long as 1)
you use it consistently, and 2) it makes the code easier to read,
understand, and maintain *for you*. Style does matter to an extent
(code that's correct and readable is preferable to code that's correct
and unreadable), but not so much that it's worth spending more than 10
minutes worrying about.
 
T

Tom St Denis

If you're coding for yourself, it doesn't really matter, as long as 1)
you use it consistently, and 2) it makes the code easier to read,
understand, and maintain *for you*.  Style does matter to an extent
(code that's correct and readable is preferable to code that's correct
and unreadable), but not so much that it's worth spending more than 10
minutes worrying about.

In general, it's more important to spend time up front making things
futureproofed than it is to let some future person figure things
out...

Tom
 
S

Seebs

I just would like to ask you for a quick answer to this question:
which style guide or style rules do you recommend me to use when
writing C code? It would be great if many of you would answer, so we
all could have here a thread with a good summary about this subject.

I use 1TBS (the K&R indentation style) for indenting, because there
is nothing any closer to an authoritative standard to be had. There's
arguments for and against a whole lot of styles; the only way to resolve
it is to appeal to authority, and K&R are authority.

More generally, I like both the Linux and BSD style guides. I particularly
like the part of the Linux style guide which says to get a copy of the GNU
coding standards and burn them. :p

-s
 
N

Nick Keighley

The "simple rule" regarding include files isn't very practical,

quote:

"Include files
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. Multiple
inclusions are a bane of systems programming. It's not rare to have
files included five or more times to compile a single C source file.
The Unix /usr/include/sys stuff is terrible this way."

"There's a little dance involving #ifdef's that can prevent a
file being read twice, but it's usually done wrong in practice - the
#ifdef's are in the file itself, not the file that includes it. The
result is often thousands of needless lines of code passing through
the lexical analyzer, which is (in good compilers) the most expensive
phase.

Just follow the simple rule."

so, no it it isn't very practical. I was almost tempted to put an
exclamation mark there. This, to me, is so obvious it doesn't need
saying. But Rob Pike is a smart guy and it isn't obvious to him!
though I can appreciate the logic and the sentiment.

I can't.

In practice there are too many issues.

it's bad in theory and worse in practice.

First, most engineers are extremely annoyed by this practice. It means they
actually have to read your code (or documentation, even!). That's too much
to expect of others, for better or worse.

exactly, it's a violation of encapsulation at the source level. If
this were car design you'd have to read a manual and carburettor
design before you started your car. Good engineering (and programming
is a branch of engineering) requires well encapsulated abstractions.
Black boxes. A bridge builder doesn't need to know how every bolt is
manufactured just that it will bear a certain load. You don't need to
read every line of source to use a library. You don't need to read of
list of comments to work out what list of includes to use.

"machines should work, people should think"
Second, the rule is, frankly, too simple. Should I force people to
separately include <stddef.h> because my header uses size_t? <limits.h> for
LONG_MAX? Many engineers will as a matter of course include <stdio.h>,
<stdlib.h>,

more fool them. Why not just include the right headers?
and other boilerplate in the first few lines of their source
file. The whole exercise is lost on them, anyhow. If things break they'll be
completely baffled one way or the other.

perhaps they should try less demanding work...
Third, there are better ways to avoid the real evils. If my code needs to
use some huge library with a gazillion namespace polluting macros and
declarations, rather than expose this dependency in my header, I should use
encapsulation such that there's no source-level dependency to bother other
engineers.

yes. Only expose things in the interface that need to be exposed
Even better, reduce dependencies altogether. It annoys me when
some library depends on glib just to re-use some simple data structure.
Forcing me to deal with those headers adds insult to injury. Pike's
/usr/include/sys example is atypical for a multitude of reasons.

because it's broken as well
The include guard hack is lamentable, but stems from fundamental quirks and
simplicities in the language design. It shouldn't be avoided merely because
the hack itself is ugly.

This is an interesting read: "Large-Scale C++ Software Design" Lakos,
John. Yes it's C++ but it still makes some interesting points. Even
for C++ its a bit dated (they invented namespaces) but apparently
there's nothing more modern on the subject
 
B

Ben Bacarisse

Nick Keighley said:
quote:

"Include files
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. Multiple
inclusions are a bane of systems programming. It's not rare to have
files included five or more times to compile a single C source file.
The Unix /usr/include/sys stuff is terrible this way."

"There's a little dance involving #ifdef's that can prevent a
file being read twice, but it's usually done wrong in practice - the
#ifdef's are in the file itself, not the file that includes it. The
result is often thousands of needless lines of code passing through
the lexical analyzer, which is (in good compilers) the most expensive
phase.

Just follow the simple rule."

so, no it it isn't very practical.

You say that as if it follows in an obvious way from what you quoted.
It seems to me to be more subtle than that.
I was almost tempted to put an
exclamation mark there. This, to me, is so obvious it doesn't need
saying. But Rob Pike is a smart guy and it isn't obvious to him!


I can't.



it's bad in theory and worse in practice.

I don't see any theoretical issue here. The style rule seems to be
almost entirely practical rather than theoretical. In fact, it seems
to be motivated by compile times.
exactly, it's a violation of encapsulation at the source level. If
this were car design you'd have to read a manual and carburettor
design before you started your car.

That's not a helpful analogy. Programming is not like driving. There
is no hope that, in C, you can make programming so simple that it is
analogous to driving a car.
Good engineering (and programming
is a branch of engineering) requires well encapsulated abstractions.
Black boxes. A bridge builder doesn't need to know how every bolt is
manufactured just that it will bear a certain load. You don't need to
read every line of source to use a library. You don't need to read of
list of comments to work out what list of includes to use.

Here, I think, is the heart of the issue. If I design my
library/component/whatever so as to be as cleanly encapsulated as
possible then the rule in question simply does not come into play
because it won't need any other includes. The problem is that this is
not always possible in C. It is not even always desirable because
people use C for speed and it is often better to expose a dependency
than to wrap up a component so thoroughly that the linkage is hidden.

So, given that we will have reduced these linkages as far as good
design and practicality allows, the rule boils down to the pros and
cons of nested includes. You seem to be saying that good engineering
practise requires that a component should be usable in a complex
system without having to understand how to interface to it. I can see
that there is obviously some advantage to that, but it certainly is
not common in other parts of engineering. You can't pick a pump and
add it to your car design without reading up on how it interfaces with
the rest of the design (connection sizes, pressures, voltage and power
requirements, etc).

[Aside: I'd say that the fact that in programming we can sometimes
achieve this level of "plug and play" between components (not usually
in C, but it is somewhat easier in other languages) is one of the
reasons why programming is not like other engineering disciplines.]

I don't think there is much to choose between the two approaches. It
seems cleaner to me to document include files dependencies than to
include the required files directly, but I would not be unhappy to
work in team that required either rule. My leaning towards the Pike
rule is largely a matter of taste (not a trivial thing, by the way,
but not one that is easy to characterise) and I am posting simply
because I don't understand why you are so sure that is hopelessly
impractical and "theoretically bad".
"machines should work, people should think"


more fool them. Why not just include the right headers?


perhaps they should try less demanding work...


yes. Only expose things in the interface that need to be exposed

Everyone agrees on this. The Pike style does not alter what is or is
not exposed. It does make the linkage more explicit, but not in a way
that makes things unmanageable (at least that has been my limited
experience).

Another thing worth a mention: the Pike style can be converted to the
other by writing a "my-module-non-pike.h" header file that includes
the documented includes from "my-module.h". It seems to be the more
flexible starting point at least. Unpicking an existing net of nested
includes is quite hard by comparison.

<snip>
 
E

Ersek, Laszlo


I'm not certain the last section is still relevant (page was last
modified ont 1998-May-15 22:22:53).

----v----
Include files

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. Multiple inclusions
are a bane of systems programming. It's not rare to have files included
five or more times to compile a single C source file. The Unix
/usr/include/sys stuff is terrible this way.

There's a little dance involving #ifdef's that can prevent a file
being read twice, but it's usually done wrong in practice - the #ifdef's
are in the file itself, not the file that includes it. The result is
often thousands of needless lines of code passing through the lexical
analyzer, which is (in good compilers) the most expensive phase.

Just follow the simple rule.
----^----

a) I think if a header declares a function with external linkage then it
should also declare all necessary function parameter types. A single
inclusion should make all constructs declared there completely usable.
For example, if you provide

int mangle_context(struct context *ctx);

in "mangle_context.h", then inclusion of "mangle_context.h" should make
immedately possible to create/initialize (at least) such an object.
Either an initialization function taking a pointer and a complete struct
declaration (so that manual auto allocation / sizeof is possible), or an
incomplete ("opaque") declaration and a "factory" function (like
fopen()).

For example, C99 7.20.3.3 "The malloc function" gives the following
synopsis for malloc():

----v----
#include <stdlib.h>
void *malloc(size_t size);
----^----

and 7.20 "General utilities <stdlib.h>" refers to 7.17 "Common
definitions <stddef.h>" when introducing "size_t" (among others).
Indeed, the standard doesn't talk about the inclusion of <stddef.h>, but
<stdlib.h> makes "size_t" visible and its definition obviously cannot
clash with that in <stddef.h>.

Thus I see my general guideline about making everything needed available
vindicated. Then the programmer is left with a choice how to implement
this in his/her own headers. One is explicitly repeating declarations,
which I find horrendous, and the other is recursive inclusion.


b) "the lexical analyzer [...] is (in good compilers) the most expensive
phase" -- I'm not sure what Rob Pike thinks about gcc, but gcc's -O
options increase compilation time noticeably. I'd think the translation
phases commonly implemented with a separate preprocessor program are the
computationally least intensive.

Even though ccache [0] states

----v----
ccache is a compiler cache. It acts as a caching pre-processor to C/C++
compilers, using the -E compiler switch and a hash to detect when a
compilation can be satisfied from cache. This often results in a 5 to 10
times speedup in common compilations.
----^----

it's not spelled out wheter that compilation time saved by ccache was IO
or CPU dominated. I'd figure the former; hard disk seeks are very slow,
and commonly used declarations are scattered over a lot of small files.
Simply serializing an inclusion-tree as a single sequentially allocated
file should be a huge performance benefit (which should probably vanish
with a warm buffer cache), and has nothing to do with the amount of text
the lexer has to tokenize. Thus the speedup won by ccache doesn't prove
Rob Pike's point (unless he also meant IO-time, which I doubt).

Cheers,
lacos

[0] http://ccache.samba.org/
 
M

Michael Tsang

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Nick said:
quote:

"Include files
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. Multiple
inclusions are a bane of systems programming. It's not rare to have
files included five or more times to compile a single C source file.
The Unix /usr/include/sys stuff is terrible this way."

"There's a little dance involving #ifdef's that can prevent a
file being read twice, but it's usually done wrong in practice - the
#ifdef's are in the file itself, not the file that includes it. The
result is often thousands of needless lines of code passing through
the lexical analyzer, which is (in good compilers) the most expensive
phase.

Just follow the simple rule."

so, no it it isn't very practical. I was almost tempted to put an
exclamation mark there. This, to me, is so obvious it doesn't need
saying. But Rob Pike is a smart guy and it isn't obvious to him!


I can't.



it's bad in theory and worse in practice.



exactly, it's a violation of encapsulation at the source level. If
this were car design you'd have to read a manual and carburettor
design before you started your car. Good engineering (and programming
is a branch of engineering) requires well encapsulated abstractions.
Black boxes. A bridge builder doesn't need to know how every bolt is
manufactured just that it will bear a certain load. You don't need to
read every line of source to use a library. You don't need to read of
list of comments to work out what list of includes to use.

"machines should work, people should think"


more fool them. Why not just include the right headers?


perhaps they should try less demanding work...


yes. Only expose things in the interface that need to be exposed


because it's broken as well


This is an interesting read: "Large-Scale C++ Software Design" Lakos,
John. Yes it's C++ but it still makes some interesting points. Even
for C++ its a bit dated (they invented namespaces) but apparently
there's nothing more modern on the subject

I support the exact opposite: include-file should be self-containing.
Including it should enable us to use everything inside it directly.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAktVwg8ACgkQm4klUUKw07A7DgCZARwgYD8pZ7qzJn2w24J2XhdY
SFMAnifk57Ex6ZgXiNgpwsbDSXXhVBp9
=iZ31
-----END PGP SIGNATURE-----
 
K

Keith Thompson

[...]
[quoting Pike]
[...]
I support the exact opposite: include-file should be self-containing.
Including it should enable us to use everything inside it directly.

I agree.

One problem with Pike's rule is the following scenario:

/* myfile.c */
#include "yourheader.h"
/* ... */

You provide me with a list of the other headers I need to include
before including "yourheader.h". In version 2.0, that list changes.
But the changes only affect declarations that are private to
"yourheader.h". For example, it might define a new struct member,
but one that's not intended to be used by client code. Following
Pike's rule, I have to update "myfile.c" (and possibly use a nasty
maze of #ifdefs if I might need to compile "myfile.c" on a system
that only has version 1.0 of "yourheader.h"). If "yourheader.h"
is self-contained, all I have to do is recompile.

Headers very often have declarations that are not intended to be
used by client code (see, for example, the definition of FILE in
<stdio.h>). Pike's rule causes client source code to be affected
by those declarations.
 
R

Richard Tobin

b) "the lexical analyzer [...] is (in good compilers) the most expensive
phase" -- I'm not sure what Rob Pike thinks about gcc, but gcc's -O
options increase compilation time noticeably.

I don't know when Pike originally made that comment, but it was a
commonly-expressed view 30 years ago. Optimisation is much more
sophisticated now, and I doubt he would say the same today.

-- Richard
 
T

Tim Rentsch

Ben Bacarisse said:
[... the rob pike rule that include files not do other includes ...]
Good engineering (and programming
is a branch of engineering) requires well encapsulated abstractions.
Black boxes. A bridge builder doesn't need to know how every bolt is
manufactured just that it will bear a certain load. You don't need to
read every line of source to use a library. You don't need to read of
list of comments to work out what list of includes to use.

Here, I think, is the heart of the issue. If I design my
library/component/whatever so as to be as cleanly encapsulated as
possible then the rule in question simply does not come into play
because it won't need any other includes. The problem is that this is
not always possible in C. [snip]

I found this last sentence surprising. Can you elaborate
or give an example of when it isn't possible to bundle
up an include file so nothing else needs to be included
to use it?
 
B

Ben Bacarisse

Tim Rentsch said:
Ben Bacarisse said:
[... the rob pike rule that include files not do other includes ...]
Good engineering (and programming
is a branch of engineering) requires well encapsulated abstractions.
Black boxes. A bridge builder doesn't need to know how every bolt is
manufactured just that it will bear a certain load. You don't need to
read every line of source to use a library. You don't need to read of
list of comments to work out what list of includes to use.

Here, I think, is the heart of the issue. If I design my
library/component/whatever so as to be as cleanly encapsulated as
possible then the rule in question simply does not come into play
because it won't need any other includes. The problem is that this is
not always possible in C. [snip]

I found this last sentence surprising. Can you elaborate
or give an example of when it isn't possible to bundle
up an include file so nothing else needs to be included
to use it?

No, because that is not what I was trying to say. I was thinking of
this: consider, say, a file-tree walking interface. It can choose to
hide all the normal bit masks used by the stat function by providing
its own (just those that are needed to do things like find all FIFOs
or all plain files etc.) or it can choose to depend on sys/stat.h (or
whatever).

I wanted to stress that there are two things going on, encapsulation
and dependence. Perfect encapsulation will mean there are next to no
dependencies between header files. Imperfect encapsulation is, for
perfectly sounds reasons, the norm for C program so there is an issue
with header files, one solution to which is Pike's rule.
 
I

Ian Collins

Tim said:
Ben Bacarisse said:
[... the rob pike rule that include files not do other includes ...]
Good engineering (and programming
is a branch of engineering) requires well encapsulated abstractions.
Black boxes. A bridge builder doesn't need to know how every bolt is
manufactured just that it will bear a certain load. You don't need to
read every line of source to use a library. You don't need to read of
list of comments to work out what list of includes to use.
Here, I think, is the heart of the issue. If I design my
library/component/whatever so as to be as cleanly encapsulated as
possible then the rule in question simply does not come into play
because it won't need any other includes. The problem is that this is
not always possible in C. [snip]

I found this last sentence surprising. Can you elaborate
or give an example of when it isn't possible to bundle
up an include file so nothing else needs to be included
to use it?

It may be a different tack, but I've seen projects use a common kitchen
sink include file in order to exploit a compiler's precompiled header
capability.
 
N

Nick Keighley

You say that as if it follows in an obvious way from what you quoted.
It seems to me to be more subtle than that.

hence the rest of my post
I don't see any theoretical issue here.

theory says you should encapsualate your modules well. Information
that isn't needed for usage should be hidden from the user.

 The style rule seems to be
almost entirely practical rather than theoretical.  In fact, it seems
to be motivated by compile times.

so for practical reasons he's going against theoretically better
practices. I'm not convinced the (theoretical!) gains in compilation
time are worth the (practical!) increase in mantenance cost.

If it made a lot of difference I might be tempted to write a tool that
did the header maintenance for me. And no, I haven't got very far in
working out how susch a tool would work.
That's not a helpful analogy.  Programming is not like driving.  There
is no hope that, in C, you can make programming so simple that it is
analogous to driving a car.

I knew someone who was of the opinion that nobody should be permitted
to drive a car until they could descibe how a clutch worked. I
consider this a violation of the black-box principle analogous to
having to know internals of a library before you can use it. I admit
argument by analogy is often flawed.
Here, I think, is the heart of the issue.  If I design my
library/component/whatever so as to be as cleanly encapsulated as
possible then the rule in question simply does not come into play
because it won't need any other includes.  The problem is that this is
not always possible in C.

or requires heroic effort. I'm almost tempted to argue that it could
be done by building a completely opaque abstraction. But I suspect it
would be a complete pain and may become insupperably difficult when
integrating a large diverse system. I'm still thinking about this.

 It is not even always desirable because
people use C for speed and it is often better to expose a dependency
than to wrap up a component so thoroughly that the linkage is hidden.

yes, though I'm not sure they always gain as much speed as they think
they do.
So, given that we will have reduced these linkages as far as good
design and practicality allows, the rule boils down to the pros and
cons of nested includes.
yes



 You seem to be saying that good engineering
practise requires that a component should be usable in a complex
system without having to understand how to interface to it.  

no. I'm saying a few of the the internals as possible should be
exposed.

I can see
that there is obviously some advantage to that, but it certainly is
not common in other parts of engineering.  You can't pick a pump and
add it to your car design without reading up on how it interfaces with
the rest of the design (connection sizes, pressures, voltage and power
requirements, etc).

now I'm straining for an analogy. Other posters have pointed out that
using Pike's Rule exposes you changes in how the headers are
orgainised. I've written socket libraries that have to be reorganised
every time they are ported between Unixen. What's in what header
changes. So the user of such a library would be forced to change with
each port.

I suspect a laptop motherboard isn't redesigned for US/UK/EUR etc.
differences in electrical supply systems.
[Aside: I'd say that the fact that in programming we can sometimes
achieve this level of "plug and play" between components (not usually
in C, but it is somewhat easier in other languages) is one of the
reasons why programming is not like other engineering disciplines.]

other disciplines try and define standard interfaces. Chips,
electrical interfaces, buses, standard nuts and bolts etc.
I don't think there is much to choose between the two approaches.  It
seems cleaner to me to document include files dependencies than to
include the required files directly, but I would not be unhappy to
work in team that required either rule.  My leaning towards the Pike
rule is largely a matter of taste (not a trivial thing, by the way,
but not one that is easy to characterise) and I am posting simply
because I don't understand why you are so sure that is hopelessly
impractical and "theoretically bad".

I haven't been on a project that used the Pike Rule heavily but I'd be
worried about an avalanche of changes triggered by a small
reorgainisation.
 
T

Tim Rentsch

Ben Bacarisse said:
Tim Rentsch said:
Ben Bacarisse said:
[... the rob pike rule that include files not do other includes ...]

Good engineering (and programming
is a branch of engineering) requires well encapsulated abstractions.
Black boxes. A bridge builder doesn't need to know how every bolt is
manufactured just that it will bear a certain load. You don't need to
read every line of source to use a library. You don't need to read of
list of comments to work out what list of includes to use.

Here, I think, is the heart of the issue. If I design my
library/component/whatever so as to be as cleanly encapsulated as
possible then the rule in question simply does not come into play
because it won't need any other includes. The problem is that this is
not always possible in C. [snip]

I found this last sentence surprising. Can you elaborate
or give an example of when it isn't possible to bundle
up an include file so nothing else needs to be included
to use it?

No, because that is not what I was trying to say. I was thinking of
this: consider, say, a file-tree walking interface. It can choose to
hide all the normal bit masks used by the stat function by providing
its own (just those that are needed to do things like find all FIFOs
or all plain files etc.) or it can choose to depend on sys/stat.h (or
whatever).

Okay, I'm with you so far.
I wanted to stress that there are two things going on, encapsulation
and dependence. Perfect encapsulation will mean there are next to no
dependencies between header files. Imperfect encapsulation is, for
perfectly sounds reasons, the norm for C program so there is an issue
with header files, one solution to which is Pike's rule.

Ah ha. I understand now why I didn't understand before.
The "this" in your earlier posting -- ambiguity there.

ISTM that the uses of "encapsulation" in Nick's posting and Ben's
posting are a shade different in their meanings. Certainly the sense
I got from Nick's comment was different from the sense I got from
Ben's comment. (Mind you, I'm not saying either one was better or
worse, or right or wrong, just that they are different.) That also
may have contributed to the confusion.
 
B

Ben Bacarisse

Nick Keighley said:
hence the rest of my post

OK. It was the "so" that made me think you thought it self-evident.
theory says you should encapsualate your modules well. Information
that isn't needed for usage should be hidden from the user.

I think we are talking about two different things. No one is arguing
again encapsulation, but since perfect encapsulation is often not
possible in C we are left with how we deal with the required includes.
I don't see much in way of theoretical reasoning to prefer one method
over the other.

or requires heroic effort. I'm almost tempted to argue that it could
be done by building a completely opaque abstraction. But I suspect it
would be a complete pain and may become insupperably difficult when
integrating a large diverse system. I'm still thinking about this.

This is, of course, why so many modern languages have something akin
to name-spaces along some mechanism for controlling the visibility of
name outside a name-space and for managing the importing of names into
one.
yes, though I'm not sure they always gain as much speed as they think
they do.


no. I'm saying a few of the the internals as possible should be
exposed.

Agreed, but this issue is solely what do to with those that /are/
exposed. If my function returns bool, do I #include <stdbool.h> in
myheader.h or document that stdbool.h is required.

One (small) advantage of not nesting includes is that I can deal with
incomplete standard implementations more easily by providing just
enough of my own definitions to include the module's header. I
suspect that I started to favour the Pike rule in the days when even
string.h had no standard name. I have started to lean away from this
view as C standards have taken hold, but old habits die hard.
now I'm straining for an analogy. Other posters have pointed out that
using Pike's Rule exposes you changes in how the headers are
orgainised. I've written socket libraries that have to be reorganised
every time they are ported between Unixen. What's in what header
changes. So the user of such a library would be forced to change with
each port.

This is unarguably a down side. How bad it is, though, is debatable.
When moving code between systems like this, something has to change
and if the library author has re-organised the code for the new port
then they will also have documented the new required includes (if they
are using Pike's rule).

To make such code portable between systems, a bunch of #ifs (or
ifdefs) are going to be needed and this is one place where I think the
extra effort of "the rule" is not wasted. Systems using the nested
include method acquire get every more complex nested webs of conditional
sections and conditional includes. The result can become close to
unmanageable. Using the Pike rule, the includes are always "flat" and
the conditional code is easier to follow and maintain. This is a
subjective argument with no data, but that is common in these cases.
No one seems to study these matters formally.

I haven't been on a project that used the Pike Rule heavily but I'd be
worried about an avalanche of changes triggered by a small
reorgainisation.

Yes, that is a problem and I can't say how bad it is in practise. The
changes relate to relatively large units (include files) so that helps
to some extent.

I have seem a compromise method where the rule is kept to except for
one level if include to deals with portability between systems
(i.e. you allow #include <some-system-hdr> to be replaced by a short
include file that uses conditional to include the headers needed for
this system). This prevents arbitrary nesting and an uncontrolled
#ifdef mess whilst keeping some of the required changes under
control.

As is so often the case with these things, I would not be surprised f
the best solution was one that allowed a deal of flexibility and
common sense in the application of the rules.

<snip>
 
N

Nick Keighley

[... the rob pike rule that include files not do other includes ...]
Good engineering (and programming
is a branch of engineering) requires well encapsulated abstractions. [...]
You don't need to read of
list of comments to work out what list of includes to use.
Here, I think, is the heart of the issue.  If I design my
library/component/whatever so as to be as cleanly encapsulated as
possible then the rule in question simply does not come into play
because it won't need any other includes.  The problem is that this

this is the "this" referred to later?

is
not always possible in C. [snip]
I found this last sentence surprising.  Can you elaborate
or give an example of when it isn't possible to bundle
up an include file so nothing else needs to be included
to use it?
No, because that is not what I was trying to say.  I was thinking of
this: consider, say, a file-tree walking interface.  It can choose to
hide all the normal bit masks used by the stat function by providing
its own (just those that are needed to do things like find all FIFOs
or all plain files etc.) or it can choose to depend on sys/stat.h (or
whatever).

Okay, I'm with you so far.
I wanted to stress that there are two things going on, encapsulation
and dependence.  Perfect encapsulation will mean there are next to no
dependencies between header files.  Imperfect encapsulation is, for
perfectly sounds reasons, the norm for C program so there is an issue
with header files, one solution to which is Pike's rule.

Ah ha.  I understand now why I didn't understand before.
The "this" in your earlier posting -- ambiguity there.

ISTM that the uses of "encapsulation" in Nick's posting and Ben's
posting are a shade different in their meanings.  Certainly the sense
I got from Nick's comment was different from the sense I got from
Ben's comment.  (Mind you, I'm not saying either one was better or
worse, or right or wrong, just that they are different.)  That also
may have contributed to the confusion.

I'm a tad loose in my terminology. I necessarily consider information
hiding to be a form of ecapsulation. And I'm willing to consider
"encapsulation" to be lexical or semantic (syntactic?)
 
N

Nick Keighley

[Pike's Rule: that include files should'nt include other includes]

I think we are talking about two different things.  No one is arguing
again encapsulation, but since perfect encapsulation is often not
possible in C we are left with how we deal with the required includes.
I don't see much in way of theoretical reasoning to prefer one method
over the other.




Agreed, but this issue is solely what do to with those that /are/
exposed.  If my function returns bool, do I #include <stdbool.h> in
myheader.h or document that stdbool.h is required.

I was thinking of the names of the header files as "an internal
detail"

One (small) advantage of not nesting includes is that I can deal with
incomplete standard implementations more easily by providing just
enough of my own definitions to include the module's header.  I
suspect that I started to favour the Pike rule in the days when even
string.h had no standard name.
yuk!


 I have started to lean away from this
view as C standards have taken hold, but old habits die hard.



This is unarguably a down side.  How bad it is, though, is debatable.
When moving code between systems like this, something has to change
and if the library author has re-organised the code for the new port
then they will also have documented the new required includes (if they
are using Pike's rule).

To make such code portable between systems, a bunch of #ifs (or
ifdefs) are going to be needed and this is one place where I think the
extra effort of "the rule" is not wasted.  Systems using the nested
include method acquire get every more complex nested webs of conditional
sections and conditional includes.  

oh yes

The result can become close to
unmanageable.  Using the Pike rule, the includes are always "flat" and
the conditional code is easier to follow and maintain.  This is a
subjective argument with no data, but that is common in these cases.
No one seems to study these matters formally.
odd



Yes, that is a problem and I can't say how bad it is in practise.  The
changes relate to relatively large units (include files) so that helps
to some extent.

I have seem a compromise method where the rule is kept to except for
one level if include to deals with portability between systems
(i.e. you allow #include <some-system-hdr> to be replaced by a short
include file that uses conditional to include the headers needed for
this system).  This prevents arbitrary nesting and an uncontrolled
#ifdef mess whilst keeping some of the required changes under
control.

yes I was considering something like that

As is so often the case with these things, I would not be surprised f
the best solution was one that allowed a deal of flexibility and
common sense in the application of the rules.

common sense? This is a food fight on comp.lang.c!
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top