Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #42821 > unrolled thread

Meta-C question about header order

Started byJens Schweikhardt <usenet@schweikhardt.net>
First post2014-04-12 19:37 +0000
Last post2014-06-10 09:40 -0700
Articles 20 on this page of 69 — 15 participants

Back to article view | Back to comp.lang.c


Contents

  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 →


#42821 — Meta-C question about header order

FromJens Schweikhardt <usenet@schweikhardt.net>
Date2014-04-12 19:37 +0000
SubjectMeta-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]


#42823

FromKeith Thompson <kst-u@mib.org>
Date2014-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]


#42836

Fromglen herrmannsfeldt <gah@ugcs.caltech.edu>
Date2014-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]


#42867

FromJens Schweikhardt <usenet@schweikhardt.net>
Date2014-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]


#42871

From"BartC" <bc@freeuk.com>
Date2014-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]


#42873

FromMalcolm McLean <malcolm.mclean5@btinternet.com>
Date2014-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]


#42877

FromKaz Kylheku <kaz@kylheku.com>
Date2014-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]


#42963

FromKen Brody <kenbrody@spamcop.net>
Date2014-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]


#42824

FromRichard Damon <Richard@Damon-Family.org>
Date2014-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]


#42855

FromKaz Kylheku <kaz@kylheku.com>
Date2014-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]


#42856

FromIan Collins <ian-news@hotmail.com>
Date2014-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]


#42857

FromKaz Kylheku <kaz@kylheku.com>
Date2014-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]


#42858

FromIan Collins <ian-news@hotmail.com>
Date2014-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]


#42970

FromKen Brody <kenbrody@spamcop.net>
Date2014-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]


#42971

FromKen Brody <kenbrody@spamcop.net>
Date2014-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]


#42969

FromKen Brody <kenbrody@spamcop.net>
Date2014-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]


#42972

FromMalcolm McLean <malcolm.mclean5@btinternet.com>
Date2014-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]


#42975

FromKaz Kylheku <kaz@kylheku.com>
Date2014-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]


#42866

FromJens Schweikhardt <usenet@schweikhardt.net>
Date2014-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]


#42882

FromRichard Damon <Richard@Damon-Family.org>
Date2014-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