Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #42821 > unrolled thread
| Started by | Jens Schweikhardt <usenet@schweikhardt.net> |
|---|---|
| First post | 2014-04-12 19:37 +0000 |
| Last post | 2014-06-10 09:40 -0700 |
| Articles | 20 on this page of 69 — 15 participants |
Back to article view | Back to comp.lang.c
Meta-C question about header order Jens Schweikhardt <usenet@schweikhardt.net> - 2014-04-12 19:37 +0000
Re: Meta-C question about header order Keith Thompson <kst-u@mib.org> - 2014-04-12 13:51 -0700
Re: Meta-C question about header order glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2014-04-13 00:11 +0000
Re: Meta-C question about header order Jens Schweikhardt <usenet@schweikhardt.net> - 2014-04-13 11:40 +0000
Re: Meta-C question about header order "BartC" <bc@freeuk.com> - 2014-04-13 13:10 +0100
Re: Meta-C question about header order Malcolm McLean <malcolm.mclean5@btinternet.com> - 2014-04-13 06:29 -0700
Re: Meta-C question about header order Kaz Kylheku <kaz@kylheku.com> - 2014-04-13 14:41 +0000
Re: Meta-C question about header order Ken Brody <kenbrody@spamcop.net> - 2014-04-15 10:36 -0400
Re: Meta-C question about header order Richard Damon <Richard@Damon-Family.org> - 2014-04-12 16:58 -0400
Re: Meta-C question about header order Kaz Kylheku <kaz@kylheku.com> - 2014-04-13 03:40 +0000
Re: Meta-C question about header order Ian Collins <ian-news@hotmail.com> - 2014-04-13 16:26 +1200
Re: Meta-C question about header order Kaz Kylheku <kaz@kylheku.com> - 2014-04-13 05:02 +0000
Re: Meta-C question about header order Ian Collins <ian-news@hotmail.com> - 2014-04-13 17:21 +1200
Re: Meta-C question about header order Ken Brody <kenbrody@spamcop.net> - 2014-04-15 10:59 -0400
Re: Meta-C question about header order Ken Brody <kenbrody@spamcop.net> - 2014-04-15 11:02 -0400
Re: Meta-C question about header order Ken Brody <kenbrody@spamcop.net> - 2014-04-15 10:59 -0400
Re: Meta-C question about header order Malcolm McLean <malcolm.mclean5@btinternet.com> - 2014-04-15 08:26 -0700
Re: Meta-C question about header order Kaz Kylheku <kaz@kylheku.com> - 2014-04-15 15:56 +0000
Re: Meta-C question about header order Jens Schweikhardt <usenet@schweikhardt.net> - 2014-04-13 11:34 +0000
Re: Meta-C question about header order Richard Damon <Richard@Damon-Family.org> - 2014-04-13 15:04 -0400
Re: Meta-C question about header order Ken Brody <kenbrody@spamcop.net> - 2014-04-15 10:52 -0400
Re: Meta-C question about header order Ian Collins <ian-news@hotmail.com> - 2014-04-13 11:09 +1200
Re: Meta-C question about header order Jens Schweikhardt <usenet@schweikhardt.net> - 2014-04-13 11:47 +0000
Re: Meta-C question about header order Ian Collins <ian-news@hotmail.com> - 2014-04-14 08:54 +1200
Re: Meta-C question about header order Kaz Kylheku <kaz@kylheku.com> - 2014-04-13 21:37 +0000
Re: Meta-C question about header order Ian Collins <ian-news@hotmail.com> - 2014-04-14 09:49 +1200
Re: Meta-C question about header order Jens Schweikhardt <usenet@schweikhardt.net> - 2014-04-14 19:17 +0000
Re: Meta-C question about header order Ian Collins <ian-news@hotmail.com> - 2014-04-15 10:24 +1200
Re: Meta-C question about header order Jens Schweikhardt <usenet@schweikhardt.net> - 2014-04-16 19:58 +0000
Re: Meta-C question about header order Richard Damon <Richard@Damon-Family.org> - 2014-04-14 21:45 -0400
Re: Meta-C question about header order luser- -droog <luser.droog@gmail.com> - 2014-04-12 16:48 -0700
Re: Meta-C question about header order Jens Schweikhardt <usenet@schweikhardt.net> - 2014-04-13 11:52 +0000
Re: Meta-C question about header order Kaz Kylheku <kaz@kylheku.com> - 2014-04-13 01:04 +0000
Re: Meta-C question about header order "BartC" <bc@freeuk.com> - 2014-04-13 10:15 +0100
Re: Meta-C question about header order Malcolm McLean <malcolm.mclean5@btinternet.com> - 2014-04-13 04:06 -0700
Re: Meta-C question about header order Jens Schweikhardt <usenet@schweikhardt.net> - 2014-04-13 12:01 +0000
Re: Meta-C question about header order "BartC" <bc@freeuk.com> - 2014-04-13 13:46 +0100
Re: Meta-C question about header order Jens Schweikhardt <usenet@schweikhardt.net> - 2014-04-13 13:58 +0000
Re: Meta-C question about header order Jens Schweikhardt <usenet@schweikhardt.net> - 2014-04-13 11:29 +0000
Re: Meta-C question about header order Martin Shobe <martin.shobe@yahoo.com> - 2014-04-13 08:48 -0500
Re: Meta-C question about header order Jens Schweikhardt <usenet@schweikhardt.net> - 2014-04-13 14:25 +0000
Re: Meta-C question about header order Kaz Kylheku <kaz@kylheku.com> - 2014-04-13 15:02 +0000
Re: Meta-C question about header order Martin Shobe <martin.shobe@yahoo.com> - 2014-04-13 21:45 -0500
Re: Meta-C question about header order Malcolm McLean <malcolm.mclean5@btinternet.com> - 2014-04-14 01:16 -0700
Re: Meta-C question about header order "BartC" <bc@freeuk.com> - 2014-04-14 10:16 +0100
Re: Meta-C question about header order Richard Damon <Richard@Damon-Family.org> - 2014-04-14 21:33 -0400
Re: Meta-C question about header order Kaz Kylheku <kaz@kylheku.com> - 2014-04-14 16:25 +0000
Re: Meta-C question about header order Malcolm McLean <malcolm.mclean5@btinternet.com> - 2014-04-14 09:47 -0700
Re: Meta-C question about header order Martin Shobe <martin.shobe@yahoo.com> - 2014-04-14 13:29 -0500
Re: Meta-C question about header order Kaz Kylheku <kaz@kylheku.com> - 2014-04-14 19:31 +0000
Re: Meta-C question about header order Les Cargill <lcargill99@comcast.com> - 2014-04-14 20:03 -0500
Re: Meta-C question about header order Kaz Kylheku <kaz@kylheku.com> - 2014-04-15 01:04 +0000
Re: Meta-C question about header order Keith Thompson <kst-u@mib.org> - 2014-04-14 15:15 -0700
Re: Meta-C question about header order Richard Damon <Richard@Damon-Family.org> - 2014-04-14 22:01 -0400
Re: Meta-C question about header order "BartC" <bc@freeuk.com> - 2014-04-15 09:51 +0100
Re: Meta-C question about header order Malcolm McLean <malcolm.mclean5@btinternet.com> - 2014-04-15 06:01 -0700
Re: Meta-C question about header order "BartC" <bc@freeuk.com> - 2014-04-15 14:29 +0100
Re: Meta-C question about header order Malcolm McLean <malcolm.mclean5@btinternet.com> - 2014-04-15 10:38 -0700
Re: Meta-C question about header order Kaz Kylheku <kaz@kylheku.com> - 2014-04-15 18:27 +0000
Re: Meta-C question about header order Malcolm McLean <malcolm.mclean5@btinternet.com> - 2014-04-15 12:45 -0700
Re: Meta-C question about header order ralph <nt_consulting@yahoo.com> - 2014-04-15 22:02 -0500
Re: Meta-C question about header order Jens Schweikhardt <usenet@schweikhardt.net> - 2014-04-14 17:44 +0000
Re: Meta-C question about header order Tim Rentsch <txr@alumni.caltech.edu> - 2014-04-19 01:25 -0700
Re: Meta-C question about header order Richard Damon <Richard@Damon-Family.org> - 2014-04-19 10:30 -0400
Re: Meta-C question about header order Jens Schweikhardt <usenet@schweikhardt.net> - 2014-04-23 19:47 +0000
Re: Meta-C question about header order James Kuyper <jameskuyper@verizon.net> - 2014-04-23 15:53 -0400
Re: Meta-C question about header order Tim Rentsch <txr@alumni.caltech.edu> - 2014-06-10 09:25 -0700
Re: Meta-C question about header order Jens Schweikhardt <usenet@schweikhardt.net> - 2014-04-23 19:27 +0000
Re: Meta-C question about header order Tim Rentsch <txr@alumni.caltech.edu> - 2014-06-10 09:40 -0700
Page 1 of 4 [1] 2 3 4 Next page →
| From | Jens Schweikhardt <usenet@schweikhardt.net> |
|---|---|
| Date | 2014-04-12 19:37 +0000 |
| Subject | Meta-C question about header order |
| Message-ID | <bqtj0hF60hpU1@mid.individual.net> |
hello, world\n consider a small project of 100 C source and 100 header files. The coding rules require that only C files include headers, headers are not allowed to include other headers (not sure if this is 100% the "IWYU - Include What You Use" paradigma). The headers contain only what headers should contain: prototypes, typedefs, declarations, macro definitions. The problem: given a set of headers, determine a sequence of #include directives that avoids syntax errors due to undeclared identifiers. I.e. if "foo.h" declares type foo_t and "bar.h" uses foo_t in a prototype, "bar.h" must be included before "foo.h". I'm not a computer scientist, but it sounds as if this requires a topological sort of all the '"foo.h" needs "bar.h"' relations. Now the interesting part is: how to automate this, i.e. how to determine "this header declares identifiers A, B, C and requires X, Y, Z"? I looked at IWYU by google, but it requires a clang source tree plus some more hoop jumping and that's way too elephantine, so I gave up not knowing whether it would provide a solution. Can you think of a lightweight way to solve this? Maybe using perl, the unix tool box, make, gmake, gcc, a C lexer? Regards, Jens -- Jens Schweikhardt http://www.schweikhardt.net/ SIGSIG -- signature too long (core dumped)
[toc] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2014-04-12 13:51 -0700 |
| Message-ID | <lnvbue8e6j.fsf@nuthaus.mib.org> |
| In reply to | #42821 |
Jens Schweikhardt <usenet@schweikhardt.net> writes:
> hello, world\n
>
> consider a small project of 100 C source and 100 header files.
> The coding rules require that only C files include headers,
> headers are not allowed to include other headers (not sure if
> this is 100% the "IWYU - Include What You Use" paradigma).
That strikes me as a stupid^H^H^H^H^H^H suboptimal rule.
You'll have headers that depend on other headers, but without that
relationship being expressed in the source.
> The headers contain only what headers should contain:
> prototypes, typedefs, declarations, macro definitions.
>
> The problem: given a set of headers, determine a sequence of
> #include directives that avoids syntax errors due to undeclared
> identifiers. I.e. if "foo.h" declares type foo_t and "bar.h" uses
> foo_t in a prototype, "bar.h" must be included before "foo.h".
>
> I'm not a computer scientist, but it sounds as if this requires a
> topological sort of all the '"foo.h" needs "bar.h"' relations. Now the
> interesting part is: how to automate this, i.e. how to determine "this
> header declares identifiers A, B, C and requires X, Y, Z"? I looked
> at IWYU by google, but it requires a clang source tree plus some more
> hoop jumping and that's way too elephantine, so I gave up not knowing
> whether it would provide a solution.
>
> Can you think of a lightweight way to solve this? Maybe using perl, the
> unix tool box, make, gmake, gcc, a C lexer?
So you need to build a set of tools that would be unnecessary if you
were allowed to have #include directives in headers.
A not quite serious suggestion: Cheat.
Write your headers *sanely*, with headers #including any other
headers they need. Make sure this version of the code compiles
and executes correctly. Now all the dependencies are explicitly
specified in the #include directives.
Create a tool that analyzes the *.h and *.c files and generates *new*
.h and .c files, where the .h files have their #include directives
removed, and the .c file have any required #include directives
added in the correct order.
This only works if everyone works only on the first version of the code;
the version with #include directives in the .c files is useful only to
satisfy the arbitrary rule.
A more realistic method: Rather than having #include directives in
headers, add comments that specify the dependencies, and write a tool
that uses those comments.
Better yet: Drop the rule and use #include directives as needed.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | glen herrmannsfeldt <gah@ugcs.caltech.edu> |
|---|---|
| Date | 2014-04-13 00:11 +0000 |
| Message-ID | <lickn2$uva$1@speranza.aioe.org> |
| In reply to | #42823 |
Keith Thompson <kst-u@mib.org> wrote: > Jens Schweikhardt <usenet@schweikhardt.net> writes: >> consider a small project of 100 C source and 100 header files. >> The coding rules require that only C files include headers, >> headers are not allowed to include other headers (not sure if >> this is 100% the "IWYU - Include What You Use" paradigma). > That strikes me as a stupid^H^H^H^H^H^H suboptimal rule. > You'll have headers that depend on other headers, but without that > relationship being expressed in the source. >> The headers contain only what headers should contain: >> prototypes, typedefs, declarations, macro definitions. >> The problem: given a set of headers, determine a sequence of >> #include directives that avoids syntax errors due to undeclared >> identifiers. I.e. if "foo.h" declares type foo_t and "bar.h" uses >> foo_t in a prototype, "bar.h" must be included before "foo.h". (snip) > A not quite serious suggestion: Cheat. > Write your headers *sanely*, with headers #including any other > headers they need. Make sure this version of the code compiles > and executes correctly. Now all the dependencies are explicitly > specified in the #include directives. > Create a tool that analyzes the *.h and *.c files and generates *new* > .h and .c files, where the .h files have their #include directives > removed, and the .c file have any required #include directives > added in the correct order. How about a tool that, for each C file analyzes the .h files, then copies them in the appropriate nested order into one big .h file for each .c file. Then modifies the .c file to include the combination .h file. Only slightly different than your suggestion, but maybe different enough. -- glen
[toc] | [prev] | [next] | [standalone]
| From | Jens Schweikhardt <usenet@schweikhardt.net> |
|---|---|
| Date | 2014-04-13 11:40 +0000 |
| Message-ID | <bqvbcrFhg97U3@mid.individual.net> |
| In reply to | #42823 |
Keith Thompson <kst-u@mib.org> wrote in <lnvbue8e6j.fsf@nuthaus.mib.org>: # Jens Schweikhardt <usenet@schweikhardt.net> writes: #> hello, world\n #> #> consider a small project of 100 C source and 100 header files. #> The coding rules require that only C files include headers, #> headers are not allowed to include other headers (not sure if #> this is 100% the "IWYU - Include What You Use" paradigma). # # That strikes me as a stupid^H^H^H^H^H^H suboptimal rule. I thought the same some time ago, but was able to leave the dark side behind me and become a good jedi. # You'll have headers that depend on other headers, but without that # relationship being expressed in the source. This is exactly what I want to avoid. I *want* the dependencies to be as clear as possible. I want to look at the include directives and have them stare right at me; it helps me realize when there is too much interdependency emerging and rethink modularization and write smaller sexier interfaces. Sprinkling yet another include in yet another header is just piling mess upon mess. Regards, Jens -- Jens Schweikhardt http://www.schweikhardt.net/ SIGSIG -- signature too long (core dumped)
[toc] | [prev] | [next] | [standalone]
| From | "BartC" <bc@freeuk.com> |
|---|---|
| Date | 2014-04-13 13:10 +0100 |
| Message-ID | <N9v2v.73192$ps2.72815@fx16.am4> |
| In reply to | #42867 |
"Jens Schweikhardt" <usenet@schweikhardt.net> wrote in message news:bqvbcrFhg97U3@mid.individual.net... > Keith Thompson <kst-u@mib.org> wrote > in <lnvbue8e6j.fsf@nuthaus.mib.org>: > # Jens Schweikhardt <usenet@schweikhardt.net> writes: > #> hello, world\n > #> > #> consider a small project of 100 C source and 100 header files. > #> The coding rules require that only C files include headers, > #> headers are not allowed to include other headers (not sure if > #> this is 100% the "IWYU - Include What You Use" paradigma). > # > # That strikes me as a stupid^H^H^H^H^H^H suboptimal rule. > > I thought the same some time ago, but was able to leave the > dark side behind me and become a good jedi. > > # You'll have headers that depend on other headers, but without that > # relationship being expressed in the source. > > This is exactly what I want to avoid. I *want* the dependencies to be as > clear as possible. I want to look at the include directives and have > them stare right at me; it helps me realize when there is too much > interdependency emerging and rethink modularization and write smaller > sexier interfaces. (I've been roundly castigated, and called a 'troll' to boot, for daring to talk about non-C language ideas in this group, so I'm taking my life in my hands here, but here goes...) I have converted a project (of maybe 16 or so modules) from C source using traditional headers, into a scheme that uses 'import' statements (you say what module you're importing and it takes care of the details). However, the C approach was much more straightforward! Instead of a single line such as: #include "header.h" which took care of everything, and was exactly the same in every module, each module now had from six to twelve import statements, different for each module. You need to be ultra-aware of interdependencies, module hierarchy etc, and to my mind it's a lot more work. Maybe that discipline is a good thing, and can help create modules with better-defined interfaces that can then be more easily used in other projects. But it also has its headaches! However, even such a scheme doesn't give a full list of dependencies: each module only lists the imports it directly needs directly. You've made a reasonably good case for having declare everything, but I'm not sure that's workable. Because the libraries, headers, whatever resources a particular header might need for its workings, should be a private (encapsulated) part of it. Otherwise when you next compile an updated version, you might have a bunch of compilation errors to sort out! -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.mclean5@btinternet.com> |
|---|---|
| Date | 2014-04-13 06:29 -0700 |
| Message-ID | <6c97dd27-ac57-431d-8165-b8c12c19ddcd@googlegroups.com> |
| In reply to | #42867 |
On Sunday, April 13, 2014 12:40:11 PM UTC+1, Jens Schweikhardt wrote:
> Keith Thompson <kst-u@mib.org> wrote
>
>
> This is exactly what I want to avoid. I *want* the dependencies to be as
> clear as possible. I want to look at the include directives and have
> them stare right at me; it helps me realize when there is too much
> interdependency emerging and rethink modularization and write smaller
> sexier interfaces.
>
> Sprinkling yet another include in yet another header is just piling mess
> upon mess.
>
The snag is this.
image.h
type strut {dum de dum } IMAGE;
IMAGE *loadimage(char *fname);
int getpixel(IMAGE *image, int x, int y);
All very reasonable, agree?
Now we have another file
graphics.c
#include "image.h"
void antialiasedcircle(IMAGE *dest, double ox, double oy, double r)
{
dum de dum ...
getpixel(ox, oy + r);
dum de dum ...
}
All very reasonable, agree?
Now here's the snag. After developing our program, we decide to bundle all
the images into one big recourse file. So we need a new routine
IMAGE *floadimage(FILE *fp)
basically it's just the same code as loadimage(), but instead of passing a
filename, we open the big file, fseek to the image, and read from there.
But when we add floadimage to image.h, graphics.c will break. It doesn't
really have dependency on FILE *. The code is designed to work with any
IMAGE structure. It's not interested in reading things to and from disk.
We've fallen foul of the stickiness rule. A fix is often to #include
stdio.h in image.h. Paradoxically, that's for the sake of functions which
don't use stdio FILE *s, If they use a FILE *directly, they should #include
it themselves. Which means stdio.h needs include guards.
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <kaz@kylheku.com> |
|---|---|
| Date | 2014-04-13 14:41 +0000 |
| Message-ID | <20140413072042.507@kylheku.com> |
| In reply to | #42867 |
On 2014-04-13, Jens Schweikhardt <usenet@schweikhardt.net> wrote: > Keith Thompson <kst-u@mib.org> wrote > in <lnvbue8e6j.fsf@nuthaus.mib.org>: > # Jens Schweikhardt <usenet@schweikhardt.net> writes: > #> hello, world\n > #> > #> consider a small project of 100 C source and 100 header files. > #> The coding rules require that only C files include headers, > #> headers are not allowed to include other headers (not sure if > #> this is 100% the "IWYU - Include What You Use" paradigma). > # > # That strikes me as a stupid^H^H^H^H^H^H suboptimal rule. > > I thought the same some time ago, but was able to leave the > dark side behind me and become a good jedi. > > # You'll have headers that depend on other headers, but without that > # relationship being expressed in the source. > > This is exactly what I want to avoid. I *want* the dependencies to be as > clear as possible. I want to look at the include directives and have > them stare right at me; it helps me realize when there is too much > interdependency emerging and rethink modularization and write smaller > sexier interfaces. Also, here is the thing. Suppose we have a module "g" which uses some data structure and functions defined by "c" which is built up using data types "a" and "b". Module "g" might depend on "a" and "b" not only through "c", but also directly. This is why it is nice in "g.c" to also include the "a.h" and "b.h" headers. It is quite bothersome when "g.c" relies on the fact that, for instance sprintf is declared because it happens that "c.h" contains interface that have FILE * arguments, and includes <stdio.h> for that. Then "g.c" is relying on the side effect that "c.h" provides sprintf, which is brutally ugly, and shows that attempts at automatic modularity through textual preprocessing are a failure. In a language with real modularity, if we depended on a module C which depends on some types in a standard I/O library, we would not inherit that entire standard I/O library through B by accident: the module inheritance mechanism "uses interface C" would not leak through irrelevant things, because C's interface would in turn use only what it needs to, like the FILE * type. With the enlightened inclusion approach, g.c has a right to use sprintf because g.c contains, somewhere at the top, #include <stdio.h>. This satisfies a need in #include "c.h", and an *independent* need in the body of g.c. When I'm reading g.c, I'm not bothered by things like "hey this uses malloc, but it's not including <stdlib.h> anywhere!" (3 minutes later) Oh, it's picking it up via foo.h (which needs stdlib.h for ldiv_t) and foo.h is included by bar.h, which is included by xyzzy.h which g.c includes.
[toc] | [prev] | [next] | [standalone]
| From | Ken Brody <kenbrody@spamcop.net> |
|---|---|
| Date | 2014-04-15 10:36 -0400 |
| Message-ID | <lijg4m$6j0$1@dont-email.me> |
| In reply to | #42823 |
On 4/12/2014 4:51 PM, Keith Thompson wrote:
> Jens Schweikhardt <usenet@schweikhardt.net> writes:
>> hello, world\n
>>
>> consider a small project of 100 C source and 100 header files.
>> The coding rules require that only C files include headers,
>> headers are not allowed to include other headers (not sure if
>> this is 100% the "IWYU - Include What You Use" paradigma).
>
> That strikes me as a stupid^H^H^H^H^H^H suboptimal rule.
Agreed.
> You'll have headers that depend on other headers, but without that
> relationship being expressed in the source.
Then require than every header which requires some other header to be
included first document such requirements at the top. Perhaps make up a
"#pragma" line (which must be ignored by the compiler if not recognized)
that tells the reader about this:
#pragma RequiresInclude(header.h)
Or (since the "rules" require that you must be in control of these headers,
anyway) start each header with a #define that tells that the header has been
included. For example:
#define __INCLUDED_HEADER_H
(Yes, yes, I know about the starting underscore.)
Then, for any header which requires it:
#ifndef __INCLUDED_HEADER_H
#error Sorry, but you need to include HEADER.H first.
#endif
[...]
>> Can you think of a lightweight way to solve this? Maybe using perl, the
>> unix tool box, make, gmake, gcc, a C lexer?
>
> So you need to build a set of tools that would be unnecessary if you
> were allowed to have #include directives in headers.
>
> A not quite serious suggestion: Cheat.
:-)
[...]
> A more realistic method: Rather than having #include directives in
> headers, add comments that specify the dependencies, and write a tool
> that uses those comments.
Agreed. That was sort of my thinking with the "#praga" method above.
> Better yet: Drop the rule and use #include directives as needed.
I'm curious how this fits with implementation header files which #include
others?
I'm also curious as to the "logic" (assuming there is any) behind such a "rule"?
--
Kenneth Brody
[toc] | [prev] | [next] | [standalone]
| From | Richard Damon <Richard@Damon-Family.org> |
|---|---|
| Date | 2014-04-12 16:58 -0400 |
| Message-ID | <CNh2v.39400$Wy2.31318@en-nntp-16.dc1.easynews.com> |
| In reply to | #42821 |
On 4/12/14, 3:37 PM, Jens Schweikhardt wrote: > hello, world\n > > consider a small project of 100 C source and 100 header files. > The coding rules require that only C files include headers, > headers are not allowed to include other headers (not sure if > this is 100% the "IWYU - Include What You Use" paradigma). > A rule that says that a header can NOT include other headers, even if it depends on the contents of that header is, in my mind, totally broken. It totally breaks the concept of encapsulation. In my mind a header MUST include every header that it needs to be able to compile, in other words, a source file consisting of nothing but an include of a given header should compile without errors. (We also have that a source file that implements (part of) a header, should include that header as its first include, in part as a test of that principle.) The only exception would be if the header is documented to need something defined before including it as part of its API. Include Way You Use should mean that you don't have "include the world" headers, and if you removed any of the includes in your source, then you will get an error for missing definitions. This should be thought of as Include What YOU Use, so in your example below, if You use bar, and bar uses foo, but you don't, then bar really needs to inlude foo, not you. I will also point out that if you strictly want to go by this, then most standard headers violate this rule, my experience is that universally standard headers will include one or more system dependent headers which hold much of the "magic" that make the system work. To follow this rule, every program would need to have some implementation defined includes at the very begin, to meet these requirements. > The headers contain only what headers should contain: > prototypes, typedefs, declarations, macro definitions. > > The problem: given a set of headers, determine a sequence of > #include directives that avoids syntax errors due to undeclared > identifiers. I.e. if "foo.h" declares type foo_t and "bar.h" uses > foo_t in a prototype, "bar.h" must be included before "foo.h". > > I'm not a computer scientist, but it sounds as if this requires a > topological sort of all the '"foo.h" needs "bar.h"' relations. Now the > interesting part is: how to automate this, i.e. how to determine "this > header declares identifiers A, B, C and requires X, Y, Z"? I looked > at IWYU by google, but it requires a clang source tree plus some more > hoop jumping and that's way too elephantine, so I gave up not knowing > whether it would provide a solution. > > Can you think of a lightweight way to solve this? Maybe using perl, the > unix tool box, make, gmake, gcc, a C lexer? > > Regards, > > Jens >
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <kaz@kylheku.com> |
|---|---|
| Date | 2014-04-13 03:40 +0000 |
| Message-ID | <20140412201155.452@kylheku.com> |
| In reply to | #42824 |
On 2014-04-12, Richard Damon <Richard@Damon-Family.org> wrote: > On 4/12/14, 3:37 PM, Jens Schweikhardt wrote: >> hello, world\n >> >> consider a small project of 100 C source and 100 header files. >> The coding rules require that only C files include headers, >> headers are not allowed to include other headers (not sure if >> this is 100% the "IWYU - Include What You Use" paradigma). >> > > A rule that says that a header can NOT include other headers, even if it > depends on the contents of that header is, in my mind, totally broken. I used to think so fresh out of school. But actually, this style is superior because leads to much cleaner code organization and faster compilation. It keeps everything "tight". I chose this approach in the TXR project, and am very pleased with it. I understand now why some people recommend it. The compiler diagnostics are simpler. None of this: "Syntax error in line 32 of X included from line 42 of Y, included from line 15 of Z ..." Also, the dependencies are easy to understand. If you look at the list of #include directives at the top of a .c file, those are the files which, if they are touched, will trigger a re-compile of this file. And no others! It's easy to generate a dependency makefile. If we have a foo.c with these contents: #include <stdio.h> #include "a.h" #include "b.h" #include "foo.h" then the dependency rule is precisely this: foo.o: foo.c a.h b.h foo.h Done! At a glance we know all the dependencies. Our regular confrontation with these dependencies in every source file prevents us from screwing up the program with a spaghetti of creeping dependencies. > It totally breaks the concept of encapsulation. Not any more than a hammer which doesn't dispense its own nails and wooden planks. Anyway, there is no encapsulation to speak of; we are dealing with a primitive text file inclusion mechanism which doesn't even come close to solving the modularity problem. The fact that you have a Makefile (or whatever) which has to list object files breaks "encapsulation". The order in which you have to set up global initialization calls breaks "encapsulation". Proper module support in a language solves everything. You can just say "This module uses that one", and the linking, global initialization, incremental recompilation and linking are all taken care of. Emulating one small aspect of this with #includes is pointless.
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2014-04-13 16:26 +1200 |
| Message-ID | <bquhvdFb55dU5@mid.individual.net> |
| In reply to | #42855 |
Kaz Kylheku wrote: > On 2014-04-12, Richard Damon <Richard@Damon-Family.org> wrote: >> On 4/12/14, 3:37 PM, Jens Schweikhardt wrote: >>> hello, world\n >>> >>> consider a small project of 100 C source and 100 header files. >>> The coding rules require that only C files include headers, >>> headers are not allowed to include other headers (not sure if >>> this is 100% the "IWYU - Include What You Use" paradigma). >>> >> >> A rule that says that a header can NOT include other headers, even if it >> depends on the contents of that header is, in my mind, totally broken. > > I used to think so fresh out of school. > > But actually, this style is superior because leads to much cleaner code > organization and faster compilation. It keeps everything "tight". The faster compilation argument is a non-starter these days. > I chose this approach in the TXR project, and am very pleased with it. > I understand now why some people recommend it. > > The compiler diagnostics are simpler. None of this: > > "Syntax error in line 32 of X > included from line 42 of Y, > included from line 15 of Z ..." > > Also, the dependencies are easy to understand. If you look at the > list of #include directives at the top of a .c file, those are > the files which, if they are touched, will trigger a re-compile > of this file. And no others! And? > It's easy to generate a dependency makefile. If we have a foo.c > with these contents: > > #include <stdio.h> > #include "a.h" > #include "b.h" > #include "foo.h" > > then the dependency rule is precisely this: > > foo.o: foo.c a.h b.h foo.h A decent make will do this for you. > Done! At a glance we know all the dependencies. Our regular confrontation with > these dependencies in every source file prevents us from screwing up the > program with a spaghetti of creeping dependencies. > >> It totally breaks the concept of encapsulation. > > Not any more than a hammer which doesn't dispense its own nails and wooden > planks. > > Anyway, there is no encapsulation to speak of; we are dealing with a primitive > text file inclusion mechanism which doesn't even come close to solving the > modularity problem. So would you rather include and maintain all of the headers (and accompanying platform specific conditional include spaghetti) a particular library uses in every source file, or just include the library's public header? All of that crud is the encapsulation referred to here. > The fact that you have a Makefile (or whatever) which has to list object files > breaks "encapsulation". Not when bringing in a library. -- Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <kaz@kylheku.com> |
|---|---|
| Date | 2014-04-13 05:02 +0000 |
| Message-ID | <20140412214930.120@kylheku.com> |
| In reply to | #42856 |
On 2014-04-13, Ian Collins <ian-news@hotmail.com> wrote: > Kaz Kylheku wrote: >> On 2014-04-12, Richard Damon <Richard@Damon-Family.org> wrote: >>> On 4/12/14, 3:37 PM, Jens Schweikhardt wrote: >>>> hello, world\n >>>> >>>> consider a small project of 100 C source and 100 header files. >>>> The coding rules require that only C files include headers, >>>> headers are not allowed to include other headers (not sure if >>>> this is 100% the "IWYU - Include What You Use" paradigma). >>>> >>> >>> A rule that says that a header can NOT include other headers, even if it >>> depends on the contents of that header is, in my mind, totally broken. >> >> I used to think so fresh out of school. >> >> But actually, this style is superior because leads to much cleaner code >> organization and faster compilation. It keeps everything "tight". > > The faster compilation argument is a non-starter these days. Personal preference. Even if the recompile is fast thanks to the hardware, I would still rather wait 5 seconds for a recompile than 8 seconds. The faster the machines get, the less I tolerate response and turnaround time. >> I chose this approach in the TXR project, and am very pleased with it. >> I understand now why some people recommend it. >> >> The compiler diagnostics are simpler. None of this: >> >> "Syntax error in line 32 of X >> included from line 42 of Y, >> included from line 15 of Z ..." >> >> Also, the dependencies are easy to understand. If you look at the >> list of #include directives at the top of a .c file, those are >> the files which, if they are touched, will trigger a re-compile >> of this file. And no others! > > And? And, I like it; I think it is beautiful to have an explicit view of the dependencies laid out in the code. Another benefit: no ugly #ifndef SYMBOL / #define SYMBOL ... #endif crap in all the header files! Just a comment block and the definitions! >> It's easy to generate a dependency makefile. If we have a foo.c >> with these contents: >> >> #include <stdio.h> >> #include "a.h" >> #include "b.h" >> #include "foo.h" >> >> then the dependency rule is precisely this: >> >> foo.o: foo.c a.h b.h foo.h > > A decent make will do this for you. I don't know of any make that generates dependencies. Compilers do (e.g gcc -MM). This is nicer. > So would you rather include and maintain all of the headers (and > accompanying platform specific conditional include spaghetti) a > particular library uses in every source file, or just include the > library's public header? All of that crud is the encapsulation referred > to here. When we divide the program into libraries, we are adding a level to the organizational hirarchy. So it would be too pigheaded not to allow the permitted #include level to also increase by one level. The library does encapsulate; as a user of the library, I don't care about how it is divided into modules. Of course a library is a unit, and it should ideally provide one simple header (or one for each major feature area). If a library has some base definitions that are used by several features, then I'd probably want to have a header for those base definitions which must be included before the main features. But all these headers can, internally, include the detailed internal headers: all of the needed ones, in the correct order (which do not include other headers). >> The fact that you have a Makefile (or whatever) which has to list object files >> breaks "encapsulation". > > Not when bringing in a library. Actually yes. If library X also needs library Y, which also needs library Z, you will have to break encapsulation and link in all of these, even though you only have #include "X.h". The documentation for X might say that you need to initialize Y first, etc. The simplicity of #include "X.h" only goes so far.
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2014-04-13 17:21 +1200 |
| Message-ID | <bqul5uFb55dU6@mid.individual.net> |
| In reply to | #42857 |
Kaz Kylheku wrote: > On 2014-04-13, Ian Collins <ian-news@hotmail.com> wrote: >> Kaz Kylheku wrote: >>> On 2014-04-12, Richard Damon <Richard@Damon-Family.org> wrote: >>>> On 4/12/14, 3:37 PM, Jens Schweikhardt wrote: >>>>> hello, world\n >>>>> >>>>> consider a small project of 100 C source and 100 header files. >>>>> The coding rules require that only C files include headers, >>>>> headers are not allowed to include other headers (not sure if >>>>> this is 100% the "IWYU - Include What You Use" paradigma). >>>>> >>>> >>>> A rule that says that a header can NOT include other headers, even if it >>>> depends on the contents of that header is, in my mind, totally broken. >>> >>> I used to think so fresh out of school. >>> >>> But actually, this style is superior because leads to much cleaner code >>> organization and faster compilation. It keeps everything "tight". >> >> The faster compilation argument is a non-starter these days. > > Personal preference. > > Even if the recompile is fast thanks to the hardware, I would still rather wait > 5 seconds for a recompile than 8 seconds. My lost point was that in practice where the includes are included makes no real difference to the build time. > The faster the machines get, the less I tolerate response and turnaround time. I must admit I do miss being able to do crosswords during builds :) >>> I chose this approach in the TXR project, and am very pleased with it. >>> I understand now why some people recommend it. >>> >>> The compiler diagnostics are simpler. None of this: >>> >>> "Syntax error in line 32 of X >>> included from line 42 of Y, >>> included from line 15 of Z ..." >>> >>> Also, the dependencies are easy to understand. If you look at the >>> list of #include directives at the top of a .c file, those are >>> the files which, if they are touched, will trigger a re-compile >>> of this file. And no others! >> >> And? > > And, I like it; I think it is beautiful to have an explicit view of the > dependencies laid out in the code. > > Another benefit: no ugly #ifndef SYMBOL / #define SYMBOL ... #endif crap > in all the header files! Just a comment block and the definitions! Yes, but if there are platform or other outside dependencies which govern which headers a particular configuration requires, they have to be written out in each source file. If code were write once, change never this wouldn't be a problem. But it isn't (except for perl, which we all know is a write only language). >>> It's easy to generate a dependency makefile. If we have a foo.c >>> with these contents: >>> >>> #include <stdio.h> >>> #include "a.h" >>> #include "b.h" >>> #include "foo.h" >>> >>> then the dependency rule is precisely this: >>> >>> foo.o: foo.c a.h b.h foo.h >> >> A decent make will do this for you. > > I don't know of any make that generates dependencies. Compilers do (e.g gcc -MM). > > This is nicer. OK, "the build system" will do this for you! >> So would you rather include and maintain all of the headers (and >> accompanying platform specific conditional include spaghetti) a >> particular library uses in every source file, or just include the >> library's public header? All of that crud is the encapsulation referred >> to here. > > When we divide the program into libraries, we are adding a level to the > organizational hirarchy. So it would be too pigheaded not to allow the > permitted #include level to also increase by one level. > > The library does encapsulate; as a user of the library, I don't care > about how it is divided into modules. > > Of course a library is a unit, and it should ideally provide one simple header > (or one for each major feature area). No argument there then. -- Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | Ken Brody <kenbrody@spamcop.net> |
|---|---|
| Date | 2014-04-15 10:59 -0400 |
| Message-ID | <lijhh3$hke$2@dont-email.me> |
| In reply to | #42858 |
On 4/13/2014 1:21 AM, Ian Collins wrote: > Kaz Kylheku wrote: >> On 2014-04-13, Ian Collins <ian-news@hotmail.com> wrote: >>> Kaz Kylheku wrote: >>>> On 2014-04-12, Richard Damon <Richard@Damon-Family.org> wrote: >>>>> On 4/12/14, 3:37 PM, Jens Schweikhardt wrote: >>>>>> hello, world\n >>>>>> >>>>>> consider a small project of 100 C source and 100 header files. >>>>>> The coding rules require that only C files include headers, >>>>>> headers are not allowed to include other headers (not sure if >>>>>> this is 100% the "IWYU - Include What You Use" paradigma). >>>>>> >>>>> >>>>> A rule that says that a header can NOT include other headers, even if it >>>>> depends on the contents of that header is, in my mind, totally broken. >>>> >>>> I used to think so fresh out of school. >>>> >>>> But actually, this style is superior because leads to much cleaner code >>>> organization and faster compilation. It keeps everything "tight". >>> >>> The faster compilation argument is a non-starter these days. >> >> Personal preference. >> >> Even if the recompile is fast thanks to the hardware, I would still rather >> wait >> 5 seconds for a recompile than 8 seconds. > > My lost point was that in practice where the includes are included makes no > real difference to the build time. > >> The faster the machines get, the less I tolerate response and turnaround >> time. > > I must admit I do miss being able to do crosswords during builds :) > >>>> I chose this approach in the TXR project, and am very pleased with it. >>>> I understand now why some people recommend it. >>>> >>>> The compiler diagnostics are simpler. None of this: >>>> >>>> "Syntax error in line 32 of X >>>> included from line 42 of Y, >>>> included from line 15 of Z ..." >>>> >>>> Also, the dependencies are easy to understand. If you look at the >>>> list of #include directives at the top of a .c file, those are >>>> the files which, if they are touched, will trigger a re-compile >>>> of this file. And no others! >>> >>> And? >> >> And, I like it; I think it is beautiful to have an explicit view of the >> dependencies laid out in the code. >> >> Another benefit: no ugly #ifndef SYMBOL / #define SYMBOL ... #endif crap >> in all the header files! Just a comment block and the definitions! > > Yes, but if there are platform or other outside dependencies which govern > which headers a particular configuration requires, they have to be written > out in each source file. If code were write once, change never this > wouldn't be a problem. But it isn't (except for perl, which we all know is > a write only language). > >>>> It's easy to generate a dependency makefile. If we have a foo.c >>>> with these contents: >>>> >>>> #include <stdio.h> >>>> #include "a.h" >>>> #include "b.h" >>>> #include "foo.h" >>>> >>>> then the dependency rule is precisely this: >>>> >>>> foo.o: foo.c a.h b.h foo.h >>> >>> A decent make will do this for you. >> >> I don't know of any make that generates dependencies. Compilers do (e.g >> gcc -MM). >> >> This is nicer. > > OK, "the build system" will do this for you! > >>> So would you rather include and maintain all of the headers (and >>> accompanying platform specific conditional include spaghetti) a >>> particular library uses in every source file, or just include the >>> library's public header? All of that crud is the encapsulation referred >>> to here. >> >> When we divide the program into libraries, we are adding a level to the >> organizational hirarchy. So it would be too pigheaded not to allow the >> permitted #include level to also increase by one level. >> >> The library does encapsulate; as a user of the library, I don't care >> about how it is divided into modules. >> >> Of course a library is a unit, and it should ideally provide one simple >> header >> (or one for each major feature area). > > No argument there then. >
[toc] | [prev] | [next] | [standalone]
| From | Ken Brody <kenbrody@spamcop.net> |
|---|---|
| Date | 2014-04-15 11:02 -0400 |
| Message-ID | <lijhm2$hke$3@dont-email.me> |
| In reply to | #42858 |
On 4/13/2014 1:21 AM, Ian Collins wrote: > Kaz Kylheku wrote: [...] >> The faster the machines get, the less I tolerate response and turnaround >> time. > > I must admit I do miss being able to do crosswords during builds :) :-) "Way back when", a simple "make $module_name" would take 20 minutes for just the *link* phase. (And we're talking about a binary of only a few hundred K back then.) Now, "make clean all" takes less than 5 minutes for the entire package, including several libraries and over a dozen modules. [...] -- Kenneth Brody
[toc] | [prev] | [next] | [standalone]
| From | Ken Brody <kenbrody@spamcop.net> |
|---|---|
| Date | 2014-04-15 10:59 -0400 |
| Message-ID | <lijhgq$hke$1@dont-email.me> |
| In reply to | #42857 |
On 4/13/2014 1:02 AM, Kaz Kylheku wrote: > On 2014-04-13, Ian Collins <ian-news@hotmail.com> wrote: >> Kaz Kylheku wrote: [...] >>> The compiler diagnostics are simpler. None of this: >>> >>> "Syntax error in line 32 of X >>> included from line 42 of Y, >>> included from line 15 of Z ..." >>> >>> Also, the dependencies are easy to understand. If you look at the >>> list of #include directives at the top of a .c file, those are >>> the files which, if they are touched, will trigger a re-compile >>> of this file. And no others! >> >> And? > > And, I like it; I think it is beautiful to have an explicit view of the > dependencies laid out in the code. > > Another benefit: no ugly #ifndef SYMBOL / #define SYMBOL ... #endif crap > in all the header files! Just a comment block and the definitions! I assume that the comment block will explicitly state "you need to include the following headers, in this order"? [...] > Of course a library is a unit, and it should ideally provide one simple header > (or one for each major feature area). Well, the OP said that that option was off the table. Unless, of course, the "one simple header" was the only header used. (ie: it doesn't #include any other headers.) However, unless it's a trivial library, it would no longer qualify as a "simple" header. > If a library has some base definitions that are used by several features, then > I'd probably want to have a header for those base definitions which must be > included before the main features. > > But all these headers can, internally, include the detailed internal headers: > all of the needed ones, in the correct order (which do not include other > headers). Not according to the OP. Headers cannot be nested. Period. [...]
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.mclean5@btinternet.com> |
|---|---|
| Date | 2014-04-15 08:26 -0700 |
| Message-ID | <36b8b25a-0959-4be2-9f84-249ce2172cdc@googlegroups.com> |
| In reply to | #42969 |
On Tuesday, April 15, 2014 3:59:38 PM UTC+1, Ken Brody wrote: > On 4/13/2014 1:02 AM, Kaz Kylheku wrote: > > > Well, the OP said that that option was off the table. Unless, of course, > the "one simple header" was the only header used. (ie: it doesn't #include > any other headers.) However, unless it's a trivial library, it would no > longer qualify as a "simple" header. > The complexity of the interface has little to do with the complexity of the underlying code. Some libraries, like GUI libraries, expose a lot of functions, most of which just set parameters in the GUI object and redraw it. Others expose only a few functions, but ones which are very difficult to write and have lots of subroutines. Eg a grammar checker fundamentally just takes a string and returns flags for words which aren't grammatical English. But there's a lot of complexity in getting that result.
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <kaz@kylheku.com> |
|---|---|
| Date | 2014-04-15 15:56 +0000 |
| Message-ID | <20140415085534.651@kylheku.com> |
| In reply to | #42969 |
On 2014-04-15, Ken Brody <kenbrody@spamcop.net> wrote: > On 4/13/2014 1:02 AM, Kaz Kylheku wrote: >> Another benefit: no ugly #ifndef SYMBOL / #define SYMBOL ... #endif crap >> in all the header files! Just a comment block and the definitions! > > I assume that the comment block will explicitly state "you need to include > the following headers, in this order"? No; the comment block gives the all important copyright notice and license. :)
[toc] | [prev] | [next] | [standalone]
| From | Jens Schweikhardt <usenet@schweikhardt.net> |
|---|---|
| Date | 2014-04-13 11:34 +0000 |
| Message-ID | <bqvb1oFhg97U2@mid.individual.net> |
| In reply to | #42855 |
Kaz Kylheku <kaz@kylheku.com> wrote in <20140412201155.452@kylheku.com>: # On 2014-04-12, Richard Damon <Richard@Damon-Family.org> wrote: #> On 4/12/14, 3:37 PM, Jens Schweikhardt wrote: #>> hello, world\n #>> #>> consider a small project of 100 C source and 100 header files. #>> The coding rules require that only C files include headers, #>> headers are not allowed to include other headers (not sure if #>> this is 100% the "IWYU - Include What You Use" paradigma). #>> #> #> A rule that says that a header can NOT include other headers, even if it #> depends on the contents of that header is, in my mind, totally broken. # # I used to think so fresh out of school. We all did, at one time or another. The approach is attractive because it's so simple and the ugly consequences are hidden (mostly behind sheer compute power and fast disk access). # But actually, this style is superior because leads to much cleaner code # organization and faster compilation. It keeps everything "tight". # # I chose this approach in the TXR project, and am very pleased with it. # I understand now why some people recommend it. # # The compiler diagnostics are simpler. None of this: # # "Syntax error in line 32 of X # included from line 42 of Y, # included from line 15 of Z ..." # # Also, the dependencies are easy to understand. If you look at the # list of #include directives at the top of a .c file, those are # the files which, if they are touched, will trigger a re-compile # of this file. And no others! # # It's easy to generate a dependency makefile. If we have a foo.c # with these contents: # # #include <stdio.h> # #include "a.h" # #include "b.h" # #include "foo.h" # # then the dependency rule is precisely this: # # foo.o: foo.c a.h b.h foo.h # # Done! At a glance we know all the dependencies. Our regular confrontation with # these dependencies in every source file prevents us from screwing up the # program with a spaghetti of creeping dependencies. Finally someone who has seen the light, too. I have nothing to add except that if you were a girl, I'd like to marry you :-) Regards, Jens -- Jens Schweikhardt http://www.schweikhardt.net/ SIGSIG -- signature too long (core dumped)
[toc] | [prev] | [next] | [standalone]
| From | Richard Damon <Richard@Damon-Family.org> |
|---|---|
| Date | 2014-04-13 15:04 -0400 |
| Message-ID | <OcB2v.38949$rL7.3601@en-nntp-16.dc1.easynews.com> |
| In reply to | #42855 |
On 4/12/14, 11:40 PM, Kaz Kylheku wrote: > On 2014-04-12, Richard Damon <Richard@Damon-Family.org> wrote: >> On 4/12/14, 3:37 PM, Jens Schweikhardt wrote: >>> hello, world\n >>> >>> consider a small project of 100 C source and 100 header files. >>> The coding rules require that only C files include headers, >>> headers are not allowed to include other headers (not sure if >>> this is 100% the "IWYU - Include What You Use" paradigma). >>> >> >> A rule that says that a header can NOT include other headers, even if it >> depends on the contents of that header is, in my mind, totally broken. > > I used to think so fresh out of school. > > But actually, this style is superior because leads to much cleaner code > organization and faster compilation. It keeps everything "tight". > I find just the opposite, as your method adds innumerable interdependency between files. The big issue can be shown as follows: File a.c needs the functionality of b.h, so it includes that file. The header b.h, as is currently implemented and as an implementation detail needs a type defined in c.h By your standard, the documentation for b.h needs to specify that a precondition to including b.h, is to previously having included c.h, even though this dependency is an implementation detail that a.c should not need to know about. Now, in fixing some things, the implementation details for b.h change, and now it needs d.h instead. Since we had to promote an implementation detail up to the public API for the file, we have a breaking change. Now to implement the fix to b.h, the program needs to know every file that used b.h, so they can be fixed (or you just introduced an unknown number of time-bombs into your code base). These time-bombs, when they go off, are probably going to be fixed by the programmer adding the needed include d.h, but it is quite possible that they will not notice that they should remove the include for c.h > I chose this approach in the TXR project, and am very pleased with it. > I understand now why some people recommend it. > > The compiler diagnostics are simpler. None of this: > > "Syntax error in line 32 of X > included from line 42 of Y, > included from line 15 of Z ..." > For that to happen, you need to be changing multiple levels of the program at once, which is a bad idea. The first thing that should have happened after editing x.h, would be to recompile x.c, and run your tests on that module, to make sure it works. Otherwise you have to debug your whole program at once, instead of being able to debug in pieces, knowing the lower level piece work. > Also, the dependencies are easy to understand. If you look at the > list of #include directives at the top of a .c file, those are > the files which, if they are touched, will trigger a re-compile > of this file. And no others! > > It's easy to generate a dependency makefile. If we have a foo.c > with these contents: > > #include <stdio.h> > #include "a.h" > #include "b.h" > #include "foo.h" > > then the dependency rule is precisely this: > > foo.o: foo.c a.h b.h foo.h > > Done! At a glance we know all the dependencies. Our regular confrontation with > these dependencies in every source file prevents us from screwing up the > program with a spaghetti of creeping dependencies. Creating the make file is a small problem, and should be something done automatically with your tools, not done by hand. YOU shouldn't need to be able to see at a glance all the piece you ultimately depend upon, that is something that is the realm of your tools. YOUR job is to read the requirements document, choose the tools that you will build your solution on and connect them together by understanding their documentation. Hopefully, you can assume that the tools you are using "work" and do what their documentation indicates. You shouldn't need to understand the details of how it does things (at least not at this point), but use it according to the documentation. > >> It totally breaks the concept of encapsulation. > > Not any more than a hammer which doesn't dispense its own nails and wooden > planks. > > Anyway, there is no encapsulation to speak of; we are dealing with a primitive > text file inclusion mechanism which doesn't even come close to solving the > modularity problem. > > The fact that you have a Makefile (or whatever) which has to list object files > breaks "encapsulation". > > The order in which you have to set up global initialization calls breaks > "encapsulation". > > Proper module support in a language solves everything. You can just say "This > module uses that one", and the linking, global initialization, incremental > recompilation and linking are all taken care of. > > Emulating one small aspect of this with #includes is pointless. > Encapsulation does not need to be perfect to be usable. While the C model lets you peek into implementation details, it doesn't force you to. By letting encapsulation happen, you don't need to know the details, you let the compiler deal with them. It is a design tool to reduce complexity. Yes, a proper module support might force you to do things right, but the fact that the way C does things in a way that allow you to break encapsulation says it is a good idea to break it.
[toc] | [prev] | [next] | [standalone]
Page 1 of 4 [1] 2 3 4 Next page →
Back to top | Article view | comp.lang.c
csiph-web