[comp.lang.c++] Problems maintaining header files

gwu@tixdemo.tcs.com (George Wu) (01/23/91)

In article <15917@reed.UUCP>, minar@reed.bitnet (Nelson
Minar,L08,x640,7776519) writes:
|> 
|> In C, I barely managed to keep all my header files straight and organized.
|> C++ just compounds my problems.
|> 
|> main.C is what you would expect.  In the process of doing its thing,
|> it creates an instance of LineWindow and an instance of Turtle.
|> Therefore, it includes the files lineWindow.h and turtle.h
|> 
|> lineWindow.C has to include lineWindow.h, obviously, and turtle.C includes
|> turtle.h.
|> 
|> The problem is, one of the member variables in class ScreenTurtle is a
|> reference to an instance of LineWindow.  Therefore, the header turtle.h
|> must also include lineWindow.h for the class declaration.
|> 
|> So, when one goes to compile main.C, it includes lineWindow.h and then
|> later includes turtle.h which again includes lineWindow.h.  Unless I take
|> precautions (either a '#pragma once' or a series of '#ifndef .. #define')
|> the header is included twice, and class LineWindow is declared twice, and
|> the compiler gets annoyed.

     If ScreenTurtle has a member variable *pointing* to an instance of a
LineWindow, then it doesn't need to include lineWindow.h.  You can just add

class LineWindow;

to lineWindow.h.  It's sort of like a function extern declaration for
externally defined classes.  You also might be able to do this with a
reference, but I'm not sure.  Try it, and if it doesn't work, switch to a
pointer.  (Yeah, I know, some people prefer references to explicit pointers.)

|> Are constructs like '#pragma once' just entirely common in C++ headers? I
|> find them ugly..

     We've never used a #pragma, and we've got hundreds of thousands of
lines of code.  We do use the #ifndef X, #define X, /* declarations */,
#endif to surround the contents of all header files, though.

							George

----
George J Wu                           | gwu@tcs.com or uunet!tcs!gwu
Software Engineer                     | 2121 Allston Way, Berkeley, CA, 94704
Teknekron Communications Systems, Inc.| (415) 649-3752

chip@tct.uucp (Chip Salzenberg) (01/24/91)

According to minar@reed.bitnet (Nelson Minar,L08,x640,7776519):
>Unless I take precautions (either a '#pragma once' or a series of
>'#ifndef .. #define' the header is included twice ...

I routinely protect all my header files (C and C++) with both
"#ifndef FOO_H ... #define FOO_H ... #endif" and "#pragma once".

I also add "#ifdef __cplusplus ... extern "C" { ... #endif" and the
closing "}" to all my C header files.

It ain't pretty, but it avoids lots of headaches down the road.
-- 
Chip Salzenberg at Teltronics/TCT     <chip@tct.uucp>, <uunet!pdn!tct!chip>
       "If Usenet exists, then what is its mailing address?"  -- me
             "c/o The Daily Planet, Metropolis."  -- Jeff Daiell

lerman@stpstn.UUCP (Ken Lerman) (01/30/91)

In article <15917@reed.UUCP> minar@reed.bitnet (Nelson Minar,L08,x640,7776519) writes:
:
:In C, I barely managed to keep all my header files straight and organized.
:C++ just compounds my problems.

...

:
:Are constructs like '#pragma once' just entirely common in C++ headers? I
:find them ugly..

Objective-C (please hold the flames down to a dull roar) uses '#import
<foo.h>' to mean the same thing as '#include <foo.h>' except do
nothing if the file has already been imported.  This is MUCH nicer
than '#pragma once' and might be a useful addition to C++.

Ken

bertrand@eiffel.UUCP (Bertrand Meyer) (01/31/91)

From <6107@stpstn.UUCP> by lerman@stpstn.UUCP (Ken Lerman):

	> In article <15917@reed.UUCP> minar@reed.bitnet
	> (Nelson Minar,L08,x640,7776519) writes:
	> :
	> :In C, I barely managed to keep all my header files
	> straight and organized.
	> :C++ just compounds my problems.
	> ...

> Objective-C (please hold the flames down to a dull roar) uses '#import
> <foo.h>' to mean the same thing as '#include <foo.h>' except do
> nothing if the file has already been imported.  This is MUCH nicer
> than '#pragma once' and might be a useful addition to C++.

	For that matter, with Eiffel there is no need for header files
or make files of any kind. The compiler takes care of analyzing
dependencies (by analyzing the source text, which is where the
information is, and the only place where it should be) and deciding
what it needs to recompile. Of course, the language was designed
to make this possible.

	Isn't it time for the software profession to move to the
nineteen-nineties?

-- Bertrand Meyer
bertrand@eiffel.com

sabbagh@acf5.NYU.EDU (sabbagh) (02/01/91)

bertrand@eiffel.UUCP (Bertrand Meyer) writes:

>	For that matter, with Eiffel there is no need for header files
>or make files of any kind. The compiler takes care of analyzing
>dependencies (by analyzing the source text, which is where the
>information is, and the only place where it should be) and deciding
>what it needs to recompile. Of course, the language was designed
>to make this possible.

>	Isn't it time for the software profession to move to the
>nineteen-nineties?

>-- Bertrand Meyer
>bertrand@eiffel.com

Unfortuantely, Dr. Meyer has committed the one great sin of academia: he
has become religious about a single idea.  Here's why the software profession
can't move to the 1990's:

1. Eiffel isn't available on micros; C++ is.
2. Eiffel is supported by only one vendor (2 since Abajton licensed it
   to port to Mac; who knows when this will happen?).
3. Eiffel is a GREAT IDEA IN THEORY; major obstacles exist to implementing
   a lot of its great features.
4. There is far more experience with C++ on real projects than with Eiffel.

Hadil G. Sabbagh
E-mail:		sabbagh@cs.nyu.edu
Voice:		(212) 998-3125
Snail:		Courant Institute of Math. Sci.
		251 Mercer St.
		New York,NY 10012

"The difference between theory and practice in practice is always greater
 than the difference between theory and practice in theory."
						- Anon.
Disclaimer: This is not a disclaimer.

chased@rbbb.Eng.Sun.COM (David Chase) (02/01/91)

In article <1466@acf5.NYU.EDU> sabbagh@acf5.NYU.EDU (sabbagh) writes:
>bertrand@eiffel.UUCP (Bertrand Meyer) writes:
>
>>	For that matter, with Eiffel there is no need for header files
>>or make files of any kind. The compiler takes care of analyzing
>>dependencies (by analyzing the source text, which is where the
>>information is, and the only place where it should be) ...

>Unfortuantely, Dr. Meyer has committed the one great sin of academia: he
>has become religious about a single idea.  Here's why the software profession
>can't move to the 1990's:
> [remarks directed against Eiffel deleted]

I think you have missed the point; these features need not be unique
to Eiffel.  Granted, Meyer takes a more extreme position (analyze the
source text) than I do, but "header files" that are something merged
into the source text by a pre-processor are really not a very good
idea.  Separate interface files in the style of Mesa and Modula are
much more useful.  They permit easy design and implementation of
language-based tools that (in C, at least) are usually handled by
creation of yet-another meta-language (for example, Mig).  Makefiles
are unnecessary.  Data marshalling routines can be created by a
language-based tool.  (One can decide, after the fact -- "hey, I'd
like to store this data, pointers and all, on disk", and get the job
done by using a simple tool, instead of having to write a
meta-language description of the existing data structures for
processing by some other tool.)  Stub generators are another
language-based tool.  I'm not saying that these things are imposible
for C/C++, but for an interface-based language they are far far
easier.

In C++, people I know have complained about multiple copies of virtual
function tables created by declarations included in multiple files,
and have proposed a pragma to deal with this.  For a language with
designed-in "interface" files, no such problem exists (rather, it is
up to the implementation to deal with this).  For C++, pre-compiled
header files are regarded as a new and interesting problem to be
tackled; for Mesa, Modula, and their derivatives, this problem has
been solved for years.  Other approaches include compiler servers that
cache interface files for re-use.

I suppose I'm preaching to the unconvertable, but it seems unusual
that someone would damn a language feature that they haven't tried.
I've tried both, and I know which one I like better.

Note, too, that in the system I used (Modula-3) we did make use of the
pre-processor from time to time, but only for those things where it
was the most appropriate tool (e.g., OS-dependent changes to data
structures, not simulating interfaces by file inclusion).  We had a
stub generator, a data marshalling generator, a makefile generator
(because we didn't really feel like duplicating the entire function of
make), a compiler server (that cached interface files for subsequent
compiles), consistency checkers, a C-generating compiler, and an
interpreter.  We used our tools to build new tools, and we were very
productive.

David Chase
Sun (all the Modula-3 work took place at Olivetti over a period of
about 2 years)

chip@tct.uucp (Chip Salzenberg) (02/01/91)

According to bertrand@eiffel.UUCP (Bertrand Meyer):
>Isn't it time for the software profession to move to the
>nineteen-nineties?

Don't look down your nose at textual inclusion.  It has other uses
besides the common "#include <class.h>".
-- 
Chip Salzenberg at Teltronics/TCT     <chip@tct.uucp>, <uunet!pdn!tct!chip>
 "I want to mention that my opinions whether real or not are MY opinions."
             -- the inevitable William "Billy" Steinmetz

bertrand@eiffel.UUCP (Bertrand Meyer) (02/01/91)

1
 - - - - - - 

From <7091@exodus.Eng.Sun.COM> by chased@rbbb.Eng.Sun.COM (David Chase):

> I think you [i.e. Hadil G. Sabbagh] have missed [B. Meyer's] point;
> these features [no need for make files, header files etc.]
> need not be unique to Eiffel.

	Mr. Chase is quite correct. He mentions Mesa and Modula-3, and I
have no doubt that automatic dependency analysis can be implemented
in these languages. Another language for which I have seen
programming environments which perform similar work is Ada.

	A full-fledged object-oriented language does make
the problem more challenging technically (because of multiple
and repeated inheritance, cycles in the client relation etc.).
The point of my message was that for automatic dependency analysis
to work the language design has to make it possible. This is true
for Ada, Eiffel, Mesa and (from the looks of it) Modula-3.
There are undoubtedly other examples.

2
 - - - - - - -

	My message discussed a specific point (header files), mentioning
Eiffel in response to a message mentioning Objective-C. Mr. Sabbagh
used this opportunity to include general comments about Eiffel
which are more political than technical, and not connected to
the matter of header files. Let it be registered that I do
not intend to help start a general political Eiffel-C++ debate.
However I do need to correct the inaccuracies regarding Eiffel
in Mr. Sabbagh's four points:

>> 1. Eiffel isn't available on micros; C++ is.
>> 2. Eiffel is supported by only one vendor (2 since Abajton licensed it
   to port to Mac; who knows when this will happen?).

Eiffel is available on micros under Unix, although it is true
that no MS-DOS implementation is available yet. However
an independent DOS implementation, by a German company,
has been announced and will be demonstrated at CeBIT in March.
I saw an early version in October and was quite impressed.
We know of several other ongoing independent efforts.

> 3. Eiffel is a GREAT IDEA IN THEORY; major obstacles exist to
> implementing a lot of its great features.

	What does this mean? All of Eiffel features have been implemented
and are being used since 1986 by thousands of people worldwide.
Please don't propagate the ``it's like Algol 60'' myth.

> 4. There is far more experience with C++ on real projects than with
> Eiffel.

There are certainly more people using C++ today, although
there is more Eiffel usage than one would think by reading
only the current technical press.

In the absence of scientifically collected evidence, however,
there are good reasons to believe that the body of actual
object-oriented development experience (significant projects
using O-O methodology, as opposed to small experiments, or
just C programming labelled C++) is at least as strong on the
Eiffel side.

To close, the following bears repeating: my only intent
in the second part of this message is to correct inaccuracies,
not to waste any more of anyone's time on non-technical language
comparisons.
-- 
-- Bertrand Meyer
bertrand@eiffel.com

mat@mole-end.UUCP (Mark A Terribile) (02/03/91)

> >>	For that matter, with Eiffel there is no need for header files
> >>or make files of any kind. The compiler takes care of analyzing
> >>dependencies (by analyzing the source text, which is where the
> >>information is, and the only place where it should be) ...
 
> >Unfortuantely, Dr. Meyer has committed the one great sin of academia: he
> >has become religious about a single idea.  ...
 
> I think you have missed the point; these features need not be unique
> to Eiffel.  Granted, Meyer takes a more extreme position (analyze the
> source text) than I do, but "header files" that are something merged
> into the source text by a pre-processor are really not a very good
> idea.  Separate interface files in the style of Mesa and Modula are
> much more useful.  ...

All of this requires that the programming language also specify the
programming environment.  It also means that things that are built for the
language can be used for nothing else.  Is there a YACC or bison for Eiffel?
Can the `real' source be managed by the same mechanism that manages
dependencies over the Eiffel?

There are good reasons for not building the environment into the language;
the tendency to circumscribe the language is one of them.

As far as making interface seperate from the specification of the type:
That messes up such things as inline functions, or else it requires that the
symbol resolution (first part of linking) be done BEFORE code generation.  It
would be nice to have that capability, but most programming environments do
not support it, and you need the support of the environment if you want to
be sure that native code which you generate will be accepted by that
environment.

I agree that things could be better.  It might even be possible to incorporate
better things into C.  But not everything that does the gee-whizbang thing
you think you want is really better.

> I suppose I'm preaching to the unconvertable, but it seems unusual
> that someone would damn a language feature that they haven't tried.
> I've tried both, and I know which one I like better.

Well, there are some things to which *I* can be converted, and there are
others to which I cannot be converted.  Hot-shot environments that are so
smart I can't make them smarter on my terms are one thing that I will do
without, thank you.
 
> Note, too, that in the system I used (Modula-3) we did make use of the
> pre-processor from time to time, but only for those things where it
> was the most appropriate tool (e.g., OS-dependent changes to data
> structures, not simulating interfaces by file inclusion).  We had a
> stub generator, a data marshalling generator, a makefile generator
> (because we didn't really feel like duplicating the entire function of
> make), a compiler server (that cached interface files for subsequent
> compiles), consistency checkers, a C-generating compiler, and an
> interpreter.  We used our tools to build new tools, and we were very
> productive.

All well and good ... but in a circumscribed environment you couldn't have
done any of them.

Dependency generators for Make on C and C++ are rather trivial, especially
on the Sun but also on other systems; all you have to do is needle the
preprocessor.  A few lines of  ksh  will do the job.
-- 

 (This man's opinions are his own.)
 From mole-end				Mark Terribile

rfg@NCD.COM (Ron Guilmette) (02/05/91)

In article <6107@stpstn.UUCP> lerman@stpstn.UUCP (Ken Lerman) writes:
>
>Objective-C (please hold the flames down to a dull roar) uses '#import
><foo.h>' to mean the same thing as '#include <foo.h>' except do
>nothing if the file has already been imported.  This is MUCH nicer
>than '#pragma once' and might be a useful addition to C++.

Contrary to Ken's misguided opinions, #import is *not* much nicer than
#pragma once.  Quite the contrary, it is much stupider.

Consider this.  I have an include file which should only be included
at most one time during an entire compilation.  If it gets included
more than once then I'll get errors.

Now ask yourself this one question.  Is the fact that this file must
only be included once into an entire compilation a property of the
include file in question, or is it a property of all of the files
which include the include file in question?

Quite obviously, the "must only be included once" property is a property
of the "includee".  It is *not* a property of all of the "includers".
This special property should therefore be expressed by having something
special coded into the (one and only) "includee".  That way, if the
includee changes with respect to this one property, you can just change
the text of the includee and leave the text of all of the includers
alone.

It's painfully obvious that Stepstone got it bass-ackwards in Objective-C
(with their #import directive).  I guess that their existing customer
base is either too large or too stagnant to permit them to to recognize
their mistake and to convert over to using #pragma once.  Either that or
else they have a bad case of `Not Invented Here' syndrome.

Also note that `#pragma once' is likely to be portable to all existing
ANSI C environments because ANSI C requires that ANSI C preprocessors
*must* ignore all #pragmas that they do not understand.

Most ANSI C compiler will totally barf on #import however, and the ANSI C
standard gives them full permission to do so.

-- 

// Ron Guilmette  -  C++ Entomologist
// Internet: rfg@ncd.com      uucp: ...uunet!lupine!rfg
// Motto:  If it sticks, force it.  If it breaks, it needed replacing anyway.

steve@taumet.com (Stephen Clamage) (02/06/91)

rfg@NCD.COM (Ron Guilmette) writes:

>Also note that `#pragma once' is likely to be portable to all existing
>ANSI C environments because ANSI C requires that ANSI C preprocessors
>*must* ignore all #pragmas that they do not understand.

Well, it's portable only in the degenerate sense that a compiler won't
complain if it doesn't recognize #pragma once.  It might merely do
something unintended and possibly harmful.

Consider these cases:

1.  The file must not be included more than once but #pragma once is
ignored.

2.  #pragma once means something entirely different to a particular
compiler (such as turn on Customer Engineer features, which can be
turned off with #pragma offce).

If you want to port programs to different environments, don't rely on
nonstandard features.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

benson@odi.com (Benson I. Margulies) (02/06/91)

In article <3707@lupine.NCD.COM> rfg@NCD.COM (Ron Guilmette) writes:
>In article <6107@stpstn.UUCP> lerman@stpstn.UUCP (Ken Lerman) writes:
>>
>>Objective-C (please hold the flames down to a dull roar) uses '#import
>><foo.h>' to mean the same thing as '#include <foo.h>' except do
>>nothing if the file has already been imported.  This is MUCH nicer
>>than '#pragma once' and might be a useful addition to C++.
>
>Contrary to Ken's misguided opinions, #import is *not* much nicer than
>#pragma once.  Quite the contrary, it is much stupider.
>
>Consider this.  I have an include file which should only be included
>at most one time during an entire compilation.  If it gets included
>more than once then I'll get errors.

Give me any include file, and I believe that I can surround it with
enough {} and #defines to make it safely includable a second time.  It
is a traditional unix vice to build things that only work one at a
time. e.g. dbm.




-- 
Benson I. Margulies

jimad@microsoft.UUCP (Jim ADCOCK) (02/06/91)

In article <6107@stpstn.UUCP> lerman@stpstn.UUCP (Ken Lerman) writes:
|In article <15917@reed.UUCP> minar@reed.bitnet (Nelson Minar,L08,x640,7776519) writes:
|:
|:In C, I barely managed to keep all my header files straight and organized.
|:C++ just compounds my problems.
|
|...
|
|:
|:Are constructs like '#pragma once' just entirely common in C++ headers? I
|:find them ugly..
|
|Objective-C (please hold the flames down to a dull roar) uses '#import
|<foo.h>' to mean the same thing as '#include <foo.h>' except do
|nothing if the file has already been imported.  This is MUCH nicer
|than '#pragma once' and might be a useful addition to C++.

I agree.  I think its silly that the most common [and unavoidable] use
of the preprocessor requires several lines of code to program.

Likewise, one could imagine an:

#export "foo.h" 
....
#endexport

directive that [in the simplest implementations] would have the effect of
copying the code found in the enclosed section, before macro expansion,
to the file "foo.h"

Such an export section would allow one write a complete class in one 
.c file, with the required .h file generated "automatically."  Smarter
implementations could only generate a new .h section if the .c export
section changed, could cache the #export section in memory, ....