By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
425,606 Members | 2,019 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 425,606 IT Pros & Developers. It's quick & easy.

Header Files and Interfaces Yet Again

P: n/a
In the past there have been lengthy discussiions regarding the role of
header files in C++. People have been very adamat about header files
serving as in interface to the implementation. I do understand the
objective. This example may represent an interface in need of a bit of
refactoring, but it goes to demonstrate the basic idea as I understand it.

http://developer.kde.org/documentati...8h-source.html

Something came up in a different context which made me reconsider whether my
concept of interface is shared by others. It also made me realize there is
an alternative way of understanding the meaning. There are too catagories
of interface which could be intended by the use of the term.

As a motivating example consider the concept of a hardware interface. There
is a certain set of rules for connecting to, and interacting with the
interface. Usually such an interface requires the user to have prior
knowledge of how it is specified. For example, there will most likely be a
technical manual containing the interface specification. It is possible,
but less likely that an interface will be self-describing. That is, the
user would have a means of querying the interface to get its specification.

In software there are instances of both kind of interface. Until recently I
had never considered that a header file might serve as the former of these
two types of interface. That is, it might not be self-describing. Take as
an example, a header file which consists of virtually nothing but
preprocessing directives conditionally branching to another file containing
declarations and perhaps another layer of indirection.

Do you consider the implementation thus described to represent an interface?
--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
Jul 22 '05 #1
Share this Question
Share on Google+
11 Replies


P: n/a
Steven T. Hatton wrote:
In the past there have been lengthy discussiions regarding the role of
header files in C++. People have been very adamat about header files
serving as in interface to the implementation. I do understand the
objective. This example may represent an interface in need of a bit of
refactoring, but it goes to demonstrate the basic idea as I understand it.

http://developer.kde.org/documentati...8h-source.html
Something came up in a different context which made me reconsider whether my concept of interface is shared by others. It also made me realize there is an alternative way of understanding the meaning. There are too catagories
of interface which could be intended by the use of the term.

As a motivating example consider the concept of a hardware interface. There is a certain set of rules for connecting to, and interacting with the
interface. Usually such an interface requires the user to have prior
knowledge of how it is specified. For example, there will most likely be a technical manual containing the interface specification. It is possible,
but less likely that an interface will be self-describing. That is, the
user would have a means of querying the interface to get its specification.
In software there are instances of both kind of interface. Until recently I had never considered that a header file might serve as the former of these
two types of interface. That is, it might not be self-describing. Take as an example, a header file which consists of virtually nothing but
preprocessing directives conditionally branching to another file containing declarations and perhaps another layer of indirection.

Do you consider the implementation thus described to represent an

interface?

Hi,
is it really important to you whether the linguistic intuitions of your
fellows are that this is or is not an interface? Well, for what it's worth,
I would say it *is* an interface. After all, it is the means by which I
access the power provided by some library. From my point of view, however,
I will want an independent description of what acutally becomes visible to
my client code when I write

#include <foo.h>

This description in turn might be given to me by a file that looks *as if*
it was the header file foo.h actually substituted by the preprocessor. In
fact, for my own template library files, I usually write such a fake header
file containing the commented declarations for all identifiers that this
header is supposed to provide to client code. This is a convenient means of
reminding myself in a concise way of what the inscrutable actual header
file that the compiler will read is supposed to do. There is, however, no
presumption that my fake header (for me to read) and the header file
(placed in the include path of my compiler) agree. For instance, the
included header file might introduce identifiers that are not supposed to
occur in the client code but are for internal use only. Those, I would not
include within the fake header.

Now, this is just what I am doing to keep track of my small library. But it
might provide an idea for the IDE that you are thinking about (I have
followed a little bit of this discussion). Maybe, the IDE should not use
the same include path as the compiler. It would derive its knowledge from
fake haeders, ideally provided by library vendors as part of their
documentation. (As far as the STL is concerned, there would be no need for
different vendors to ship those fake headers as they would all have to
agree anyway. Thus the IDE could come preloaded with that knowledge in its
include path.) If, however, a library vendor is not so inclined, someone
else could volunteer and write the header independently. I would assume
that if the IDE idea catches on, this need will become less frequent with
time.
Best regards

Kai-Uwe
PS. A friend of mine taught me that there are two kinds of problems:
engineering problems and political problems. The difference is that
engineering problems sometimes do have solutions. As a corollary, if facing
some difficulty, it is better to find a point of view from which it appears
as an engineering problem.

Jul 22 '05 #2

P: n/a
Kai-Uwe Bux wrote:

is it really important to you whether the linguistic intuitions of your
fellows are that this is or is not an interface?
As it turns out, I've found not having a good common definion of what this
means can lead to significant communication problems.
Well, for what it's
worth, I would say it *is* an interface. After all, it is the means by
which I access the power provided by some library.
Considering my previous statements, I'd be hard pressed to disagree. But it
is certainly not a concept of interface that I have used in concjunction
with header files.
From my point of view,
however, I will want an independent description of what acutally becomes
visible to my client code when I write

#include <foo.h>

This description in turn might be given to me by a file that looks *as if*
it was the header file foo.h actually substituted by the preprocessor.
This is exactly my response to the situation.
Now, this is just what I am doing to keep track of my small library. But
it might provide an idea for the IDE that you are thinking about (I have
followed a little bit of this discussion). Maybe, the IDE should not use
the same include path as the compiler. It would derive its knowledge from
fake haeders, ideally provided by library vendors as part of their
documentation. (As far as the STL is concerned, there would be no need for
different vendors to ship those fake headers as they would all have to
agree anyway.
There are at least two potential problems with that. First, if the
implementor doesn't exactly match the headers as presented in the Standard,
I will have to adjust my headers to match the implementation. Second, the
implementors of one implementation of the Standard Library(STL is an
informal subset, I believe) have told me there are places where the
standard does not completely specify the interface, and some other problems
involving circular dependencies. I also believe there may be some places
where the standard is very specific about things being implementation
defined. For example:

namespace std {
template<class charT, class traits = char_traits<charT>,
class Allocator = allocator<charT> >
class basic_string {
public:
// types:
typedef traits traits_type;
typedef typename traits::char_type value_type;
typedef Allocator allocator_type;
typedef typename Allocator::size_type size_type;
typedef typename Allocator::difference_type difference_type;

typedef typename Allocator::reference reference;
typedef typename Allocator::const_reference const_reference;
typedef typename Allocator::pointer pointer;
typedef typename Allocator::const_pointer const_pointer;

typedef implementation defined iterator; // See
lib.container.requirements
typedef implementation defined const_iterator; // See
lib.container.requirements
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
static const size_type npos = -1;

// lib.string.cons Thus the IDE could come preloaded with that knowledge in its
include path.) If, however, a library vendor is not so inclined, someone
else could volunteer and write the header independently. I would assume
that if the IDE idea catches on, this need will become less frequent with
time.


I'm really not sure what makes your "fake" headers "fake". Stroustrup
suggest there are situations in which your approach is applicable. Are they
accessed when the user's code is compiled?

I'm hoping the people I'm dealing with will recover from the shock of my
suggesting the Standard Headers should provide such a representation, and
will cooperate with me in determining how to make the necessary
modifications to the Headers as they appear in the Standard.
--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
Jul 22 '05 #3

P: n/a
Steven T. Hatton wrote:
Kai-Uwe Bux wrote:
This description in turn might be given to me by a file that looks *as
if* it was the header file foo.h actually substituted by the
preprocessor.
This is exactly my response to the situation.
Now, this is just what I am doing to keep track of my small library. But
it might provide an idea for the IDE that you are thinking about (I have
followed a little bit of this discussion). Maybe, the IDE should not use
the same include path as the compiler. It would derive its knowledge from
fake haeders, ideally provided by library vendors as part of their
documentation. (As far as the STL is concerned, there would be no need
for different vendors to ship those fake headers as they would all have
to agree anyway.


There are at least two potential problems with that. First, if the
implementor doesn't exactly match the headers as presented in the
Standard, I will have to adjust my headers to match the implementation.


Hm, if the implementation does not match the standard, I think you have a
convincing case that the vendor should fix this. But that would be a
political approach of which I am sceptical. So, I concede that there might
be problems. However, my understanding is that compilers/libraries are
converging towards the standard. From what I was experiencing with g++
during the last year, convergence happens at a remarkable speed. Almost
every new release breaks my code. (Tells you something about my coding, I
guess :-)
Second, the implementors of one implementation of the Standard Library(STL
is an informal subset, I believe) have told me there are places where the
standard does not completely specify the interface, and some other
problems involving circular dependencies.
You probably have a way better understanding of this after all the
discussion that you have been through. I would like to know, what these
circular dependencies are. Maybe it is just that the standard puts the same
identifier into several headers, meaning that these identifiers should
become visible by including header A as well as by including header B. An
implementor might have to break this and make a decission. Or the vendor
might resort to some macro magic to deal with this. An example could be,
also I do not know if this is the case, identifiers like std::cout. This is
a static object that can certainly be declared at most once. If several
headers provide access to this identifier, it still cannot be defined in
all of them.

For, what I have called "fake headers" that would not be a problem. Just
document the identifier in both of them as including either one will make
the identifier accessible to client code. Fake headers, as I use them, just
provide information about which identifiers become visible by a certain
include directive. That is their whole purpose on my hard disc.

I should stop speculating about the meaning of "circular dependencies" as I
have to admit that I am not as deeply into this issue as to understand what
experts might have refered to. At this point, it would certainly be helpful
to have a concrete example of such a problem.
I also believe there may be some places
where the standard is very specific about things being implementation
defined. For example:

namespace std {
template<class charT, class traits = char_traits<charT>,
class Allocator = allocator<charT> >
class basic_string {
public:
// types:
typedef traits traits_type;
typedef typename traits::char_type value_type;
typedef Allocator allocator_type;
typedef typename Allocator::size_type size_type;
typedef typename Allocator::difference_type difference_type;

typedef typename Allocator::reference reference;
typedef typename Allocator::const_reference const_reference;
typedef typename Allocator::pointer pointer;
typedef typename Allocator::const_pointer const_pointer;

typedef implementation defined iterator; // See
lib.container.requirements
typedef implementation defined const_iterator; // See
lib.container.requirements
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
static const size_type npos = -1;

// lib.string.cons
I assume that the implemetation defined typedefs are bothering you? Now, I
would like to know if it was really all that good if the user (or a smart
IDE) would know or care about what these types are. Certainly, relying on
that type being what it is in a particular implemetation will make your
code non-portable. I would not want to know about this, and maybe I would
not want my IDE to care about it either. Thus, I would suggest to introduce
a special keyword implemetation_defined for the use in fake headers that
makes it clear to everybody (including IDEs) that you are supposed *not* to
know/care about this. Any programmer, who *really needs* to know will have
to find out by himself. But, that might be a good thing.

Besides, there is the additional problem that an implementation defined
type may not be a type expressible with the linguistic means of C++ at all.
It could be just a placeholder for some magic going on within the compiler.
Insisting that those types *must* be for real might come with a performance
penalty in some situations. But I start speculating again, and I do not
that much about compiler design as to asses whether this is really a
problem.
I'm really not sure what makes your "fake" headers "fake". Stroustrup
suggest there are situations in which your approach is applicable. Are
they accessed when the user's code is compiled?
That is precisely what makes them "fake": the compiler does not get to see
them at all. They are entirely for my own inspection. See, my C++ coding
style is still not very mature, and I actually prefer to not declare but to
define right away (sort of the Oberon style). Now, this makes the interface
hard to comprehend as code gets in the way. Thus, I create a second file
with all definitions turned into declarations and all the code removed.
Only the comments describing what the routines do are preserved. Also some
internal stuff, like private fields or helper classes that had to be put in
namespace level and could not be hidden are left out of the fake headers if
they are supposed to be off limits for client code. This file, the fake
header, is for my eyes only!

So the fake header is not put in the include path for my compiler but in a
doc/ directory. Of course there is a certain problem of keeping the header
file and the fake header in sync. But since my code base is not very large,
I can get away with it.

That my compiler does not look at the fake headers has an additional
advantage: they could follow the C++ syntax a little loosely. Thus keywords
like "implementation_defined" or "off_limits", which would cause a compiler
to hick up, need not be a problem for the user (or an IDE). It is not
axiomatic that fake headers *must* be usable as a possible implementation
for the actual header file. They serve a different purpose, they address a
different audience: me as a client of my own code (or an IDE that will
surely outsmart me). My fake headers do not address the compiler, which is
the audience for the actual header files.
I'm hoping the people I'm dealing with will recover from the shock of my
suggesting the Standard Headers should provide such a representation, and
will cooperate with me in determining how to make the necessary
modifications to the Headers as they appear in the Standard.


I think people take it to be your opinion that the header files as parsed
by the compiler ought to look more or less like what one would guess from
the description of these headers given in the standard. What I am
suggesting is that it might not be necessary for engineering an IDE that
the compiler and the IDE are parsing the same files. But then again, I have
not really thought about the problems one faces in designing an IDE. If it
is your informed engineering opinion that IDE and compiler need to access
identical information, you may be right. Certainly, I am not the one to
prove you wrong on this account.
Best regards

Kai-Uwe
Jul 22 '05 #4

P: n/a

"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message
news:55********************@speakeasy.net...

Do you consider the implementation thus described to represent an

interface?
Does it matter??? Is there some problem you're having?

<rant>

I honestly fail to see what the point of all your posts is. Nothing I've
seen discussed in any way helps write better code, or make projects more
manageable. And the more that respondents try to address specific
programming points that you bring up, the more esoteric your own responses
get, twisting the conversations into what amounts to philosophical drivel.
I really don't mean to flame you or anything, but I'm seriously stumped as
to why you ask such strange questions that don't seem to have any relation
to actually doing any real work. Personally, I have a job to do, and most
of the time the discussions here point out real-world issues that I need to
know about in order to accomplish those tasks. But I can't recall one of
your posts that actually led anywhere. I'm starting to wonder whether you
actually care about these problems, or if you're shooting for the troll of
the year award!

</rant>

-Howard


Jul 22 '05 #5

P: n/a
Howard wrote:

"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message
news:55********************@speakeasy.net...

Do you consider the implementation thus described to represent an interface?
Does it matter??? Is there some problem you're having?


AAMOF, yes. I encountered a problem of communication with another person
who apparently held that position, and we were both using the term
interface, but not understanding what the other person intended.
<rant>
I honestly fail to see what the point of all your posts is. Nothing I've
seen discussed in any way helps write better code, or make projects more
manageable. And the more that respondents try to address specific
programming points that you bring up, the more esoteric your own responses
get, twisting the conversations into what amounts to philosophical drivel.
I will note that _I_ did not write the above sentence.
I really don't mean to flame you or anything, but I'm seriously stumped as
to why you ask such strange questions that don't seem to have any relation
to actually doing any real work. Personally, I have a job to do, and most
of the time the discussions here point out real-world issues that I need
to
know about in order to accomplish those tasks. But I can't recall one of
your posts that actually led anywhere.
This is rally a very general issue, applicable to many design situations.
It has direct relevance to the kind of design I'm considering. It also
seems to be a point of considerable confusion in discussions about C++. If
people don't agree on what they intend by the term /interface/ in a given
context, then there is a good chance they will not productively
collaborate.

</rant>

-Howard

Please
--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
Jul 22 '05 #6

P: n/a
Kai-Uwe Bux wrote:
Steven T. Hatton wrote:
Kai-Uwe Bux wrote:
This description in turn might be given to me by a file that looks *as
if* it was the header file foo.h actually substituted by the
preprocessor.
This is exactly my response to the situation.
Now, this is just what I am doing to keep track of my small library. But
it might provide an idea for the IDE that you are thinking about (I have
followed a little bit of this discussion). Maybe, the IDE should not use
the same include path as the compiler. It would derive its knowledge
from fake haeders, ideally provided by library vendors as part of their
documentation. (As far as the STL is concerned, there would be no need
for different vendors to ship those fake headers as they would all have
to agree anyway.


There are at least two potential problems with that. First, if the
implementor doesn't exactly match the headers as presented in the
Standard, I will have to adjust my headers to match the implementation.


Hm, if the implementation does not match the standard, I think you have a
convincing case that the vendor should fix this.


Since, AFAIK, no implementation is 100% conformant, I assume their
non-compliance is something they would like to address themselves, but for
technical reasons have not found a way. Of course, I use products created
by people who strive to meed these standards.
You probably have a way better understanding of this after all the
discussion that you have been through. I would like to know, what these
circular dependencies are.
I haven't found time to study the matter much. But something seems amiss in
all of this. Or the
vendor might resort to some macro magic to deal with this. An example
could be, also I do not know if this is the case, identifiers like
std::cout. This is a static object that can certainly be declared at most
once.
Declared, or defined?
If several headers provide access to this identifier, it still
cannot be defined in all of them.
If we are speaking of Standard Headers, I have to admit, I'm not completely
clear what is intended by such statements in the Standard as:

"The entities in the C++ Standard library are defined in headers, whose
contents are made available to a translation unit when it contains the
appropriate #include preprocessing directive (_cpp.include_)."

As I understand it, this is not the same usage as Stroustrup suggests for
headers. That is, headers should present an interface to the user, (or
implementor.). The Standard clearly speaks of entities being *defined* in
headers, and not simply declared in them.

For, what I have called "fake headers" that would not be a problem. Just
document the identifier in both of them as including either one will make
the identifier accessible to client code. Fake headers, as I use them,
just provide information about which identifiers become visible by a
certain include directive. That is their whole purpose on my hard disc.
I have to confess, I am a bit confused by all of this. If I have a library
with compiled code, I can use the declarations in the headers to compile my
source, and I don't need to know about the 'definitions' until I call the
linker. Or so I believe. I am under the impression that what the
declarations provide me with are the names needed to communicate to the
linker what needs to be connected to what. So if the declarations in your
"fake" headers have "real" names in the form that the declarations would
appear, I don't understand why they would not suffice as real headers to
feed to the compiler.

Stroustrup clearly provides a notion of having two (or more) sets of
functional headers. One set might be accessed by the user of a component,
while another would be accessed by its implementor. Perhaps I'm missing
something but it appears to me the Standard Library is not designed
according to the guidelines presented in TC++PL(SE).
I should stop speculating about the meaning of "circular dependencies" as
I have to admit that I am not as deeply into this issue as to understand
what experts might have refered to. At this point, it would certainly be
helpful to have a concrete example of such a problem.
You can ask on the libstdc++ mailing list.

Interestingly the Standard says:

"A translation unit may include library headers in any order (_lex_).
Each may be included more than once, with no effect different from
being included exactly once, except that the effect of including
either <cassert> or <assert.h> depends each time on the lexically cur-
rent definition of NDEBUG.18)"

That seems to indicate that something is wrong with either the Standard, or
with the implementation.
I assume that the implemetation defined typedefs are bothering you? Now, I
would like to know if it was really all that good if the user (or a smart
IDE) would know or care about what these types are. Certainly, relying on
that type being what it is in a particular implemetation will make your
code non-portable. I would not want to know about this, and maybe I would
not want my IDE to care about it either. Thus, I would suggest to
introduce a special keyword implemetation_defined for the use in fake
headers that makes it clear to everybody (including IDEs) that you are
supposed *not* to know/care about this. Any programmer, who *really needs*
to know will have to find out by himself. But, that might be a good thing.
I believe this reveals what I was saying about the failure of the Standard
Library to conform to the guidelines Stroustrup provides in TC++PL(SE).
There should be a user interface that hides such implementation details. I
have to ask what would go in my code to correspond to these
'implementation_defined' types.

Besides, there is the additional problem that an implementation defined
type may not be a type expressible with the linguistic means of C++ at
all. It could be just a placeholder for some magic going on within the
compiler. Insisting that those types *must* be for real might come with a
performance penalty in some situations. But I start speculating again, and
I do not that much about compiler design as to asses whether this is
really a problem.
I will need to study the matter more closely before I can comment.
I'm really not sure what makes your "fake" headers "fake". Stroustrup
suggest there are situations in which your approach is applicable. Are
they accessed when the user's code is compiled?


That is precisely what makes them "fake": the compiler does not get to see
them at all. They are entirely for my own inspection. See, my C++ coding
style is still not very mature, and I actually prefer to not declare but
to define right away (sort of the Oberon style). Now, this makes the
interface hard to comprehend as code gets in the way.


Stroustrup presents (at least)two rather distinct notions of something
called an interface. One is that which I have described involving the use
of header files. The other is the use of abstract base classes as
interfaces.
Thus, I create a
second file with all definitions turned into declarations and all the code
removed. Only the comments describing what the routines do are preserved.
Also some internal stuff, like private fields or helper classes that had
to be put in namespace level and could not be hidden are left out of the
fake headers if they are supposed to be off limits for client code. This
file, the fake header, is for my eyes only!
I reiterate my questions about their 'fake' nature.

have not really thought about the problems one faces in designing an IDE.
If it is your informed engineering opinion that IDE and compiler need to
access identical information, you may be right. Certainly, I am not the
one to prove you wrong on this account.


Oh, no. I'm not the expert. But my instincts tell me it's best to have the
interface representing the Standard Libraries created in conjunction with
the implementation, and indeed, they should be the source of the
declarations used by the compiler.

I have had to refine my thinking in this regard. I believe I've actually
discussed this before in a different context on comp.std.c++. It's ironic
that people such as Stroustrup and Josuttis express opinions such as 'there
is much room for improvement' or 'the design is far from perfect', while
people who have far less personal investment in the design are overtly
hostile to critics of the current design.

There are some historical reasons that might explain their defensiveness,
however. For example, the critique by Ian Joyner probably did more to
prevent a reasonable assessment of C++ than it did to provide one. I
haven't read the whole thing, mostly because of the excesses in the parts I
have read. The fact he managed to get 10 paragraphs out of the goto
statement exemplifies this.

Stroustrup's treatmet of the goto was something on the order of. It's
there. There's little reason to ever use it.

Here's a bit of irony:
$ pwd
/usr/src/linux/kernel

Fri Jun 11 01:49:59:> grep goto *.c | wc -l
226

$ cd /download/edu/stanford/cweb

$ grep goto *.c | wc -l
37

$ grep Copyright README
% Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth

--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
Jul 22 '05 #7

P: n/a
Hi,
Steven T. Hatton wrote:
I have to confess, I am a bit confused by all of this. If I have a
library with compiled code, I can use the declarations in the headers to
compile my source, and I don't need to know about the 'definitions' until
I call the
linker. Or so I believe. I am under the impression that what the
declarations provide me with are the names needed to communicate to the
linker what needs to be connected to what. So if the declarations in your
"fake" headers have "real" names in the form that the declarations would
appear, I don't understand why they would not suffice as real headers to
feed to the compiler.
I feel the need to elaborate on what I call fake headers, any why my
compiler is not allowed to read them. I prepared a very small example to
illustrate the difference of header file and fake header. The translation
unit is supposed to provide a class "PhoneDirectory" that has only two
methods: one for entering a pair (name, number) and one for listing all
numbers associated to a given name. Here is the fake header:
// phone_directory.fake

class PhoneDirectory {
public:

void insert ( const std::string & name,
const std::string & number );
// enter a (name,number) pair.

std::list< std::string > lookup_number ( const std::string & name ) const;
// return the phone numbers associated to name.

};

// end of file
This fake header contain all the information that is needed by a programmer
to create code using this class. It does however hot serve as a header file
for the compiler. That looks like this:
// phone_directory.h

#include <map>
#include <string>
#include <list>

class PhoneDirectory {
private:

typedef std::pair< const std::string, std::string > Pair;
typedef std::multimap< std::string, std::string > Book;
Book book;

public:

void insert ( const std::string & name,
const std::string & number );
// enter a (name,number) pair.

std::list< std::string > lookup_number ( const std::string & name ) const;
// return the phone numbers associated to name.

};

// end of file
As you can see, it contains way more information:

a) it gives away implementation details as it has to list private fields
and their types.

b) it includes other headers, among them even those only needed in the
private part of the class.

The point that I hope to get across is that header files need to provide
information to the compiler that is of no concern to the programmer using
the library. Private fields of classes are of no concern whatsoever to the
user. Nonetheless, a compiler has to know about them at compile time.
Therefore, fake headers can not serve as sufficient information to the
compiler.

There are more complicated examples involving templates, where it actually
can be usefull or even necessary to give implemting code in the header
files: after all template definitions need to be known at compile time. In
those cases, the header file will be cluttered with implemtation details. A
fake header will still be small and easy to read. But this is possible
precisely because it does not need to contain all the information that the
compiler needs to instanciate templates or allocate memory for private
fields in classes.

Of course, in the simple cases I presented you can create the fake header
from the header file more or less automatically. However, there are more
tricky examples where this is not straight forward. In any case, I hope
this illustrates the difference of header file (read by the compiler) and
the fake header (meant to illustrate to a human what the library provides).

Stroustrup clearly provides a notion of having two (or more) sets of
functional headers. One set might be accessed by the user of a component,
while another would be accessed by its implementor. Perhaps I'm missing
something but it appears to me the Standard Library is not designed
according to the guidelines presented in TC++PL(SE).
I do not onw a copy of TC++PL(SE) so I cannot comment on this particular
assesment. However, why would it be necessary, better, or advisable that
the standard follows the guidlines in that book?

My understanding of the standard is that resembles my fake headers more
than it resembles header files. The reason is clear: The standard addresses
the user and not the compiler. Hence, the standard will not list any
private members and will only give template declarations which would be
clearly insufficient for a compiler. I do not see why this would be a
defect or shortcoming of the standard.

Interestingly the Standard says:

"A translation unit may include library headers in any order (_lex_).
Each may be included more than once, with no effect different from
being included exactly once, except that the effect of including
either <cassert> or <assert.h> depends each time on the lexically cur-
rent definition of NDEBUG.18)"

That seems to indicate that something is wrong with either the Standard,
or with the implementation.
Why? This requirement is probably met by most implementations. It just
states that

#include <map>
#include <list>
#inclusde <string>
#include <list>

and

#include <string>
#include <map>
#include <list>

are equivalent, i.e., once that is written the same identifiers can be used
in client code.

I assume that the implemetation defined typedefs are bothering you? Now,
I would like to know if it was really all that good if the user (or a
smart IDE) would know or care about what these types are. Certainly,
relying on that type being what it is in a particular implemetation will
make your code non-portable. I would not want to know about this, and
maybe I would not want my IDE to care about it either. Thus, I would
suggest to introduce a special keyword implemetation_defined for the use
in fake headers that makes it clear to everybody (including IDEs) that
you are supposed *not* to know/care about this. Any programmer, who
*really needs* to know will have to find out by himself. But, that might
be a good thing.


I believe this reveals what I was saying about the failure of the Standard
Library to conform to the guidelines Stroustrup provides in TC++PL(SE).
There should be a user interface that hides such implementation details.
I have to ask what would go in my code to correspond to these
'implementation_defined' types.


The typedefs in the standard make these types available to your code by
giving them names. These names are *the* means of using those
implementation_defined types in your code. What these types really are is
of no interest to the coder. (Of course, a compiler would have to know, but
that is the difference of header files and fake headers again. Again, I
think the standard provided fake headers, not header files.)

[fake headers] are entirely for my own inspection. See, my C++
coding style is still not very mature, and I actually prefer to not
declare but to define right away (sort of the Oberon style). Now, this
makes the interface hard to comprehend as code gets in the way.


Stroustrup presents (at least)two rather distinct notions of something
called an interface. One is that which I have described involving the use
of header files. The other is the use of abstract base classes as
interfaces.


I appologize for using the word interface. I will try hard not do that
again. I understand that it has become a loaden term in this discussion.

... I create a
second file with all definitions turned into declarations and all the
code removed. Only the comments describing what the routines do are
preserved. Also some internal stuff, like private fields or helper
classes that had to be put in namespace level and could not be hidden are
left out of the fake headers if they are supposed to be off limits for
client code. This file, the fake header, is for my eyes only!


I reiterate my questions about their 'fake' nature.


I gave an example of a fake header above. I hope that resolves some of your
questions about what makes my fake headers fake. If you try to use the fake
header above with the compiler, it would fail badly.

have not really thought about the problems one faces in designing an IDE.
If it is your informed engineering opinion that IDE and compiler need to
access identical information, you may be right. Certainly, I am not the
one to prove you wrong on this account.


Oh, no. I'm not the expert. But my instincts tell me it's best to have
the interface representing the Standard Libraries created in conjunction
with the implementation, and indeed, they should be the source of the
declarations used by the compiler.


This seems to be the heart of the matter. As I pointed out already, the
compiler will need to know a lot more than I want to read in the standard.
I do not want the standard to tell me about private members of the
container classes. However, I understand that you are using the rather
loose phrase "... should be the source of the declarations used by the
compiler" which does not imply that the headers as described by the
standard are usable verbatim as header files in a library. Anyway, my gut
feelings actually go opposite to your instincts. I feel that implementors
should have a lot of freedom so that they can provided highly optimized
code. All I care about is that "#include <foo>" has the effects described
in the standard. And I have to admit that I would not want the standard to
do more than list the effects associated to the lines I write. I do not
care about the underlying magic that makes these effects happen.

Moreover, if you "are not the expert", may I assume that you have some
experts on IDE design within reach? After all you seem to be highly
involved in this proect and there must be some people who would actually
try to code it. I am curious as to what they think on this matter. To be
frank, it might be a little premature to ventilate changes to the standard
before actual engineering problems in designing an IDE prove those changes
useful. Your case will become a lot stronger once you can replace "my
instincts" with some concrete experiences illustrating which limitations on
IDE design are caused by shortcomings of the language.

I have had to refine my thinking in this regard. I believe I've actually
discussed this before in a different context on comp.std.c++. It's ironic
that people such as Stroustrup and Josuttis express opinions such as
'there is much room for improvement' or 'the design is far from perfect',
while people who have far less personal investment in the design are
overtly hostile to critics of the current design.

There are some historical reasons that might explain their defensiveness,
however. For example, the critique by Ian Joyner probably did more to
prevent a reasonable assessment of C++ than it did to provide one. I
haven't read the whole thing, mostly because of the excesses in the parts
I
have read. The fact he managed to get 10 paragraphs out of the goto
statement exemplifies this.
With respect to changing a language, a good deal of conservatism seems to
be a very reasonable attitude. Certainly, I would approve of changes only
if they do not require serious rewriting of large portions of my code.
Moreover, there are certain underlying design goals that sort of govern
C++. As far as I understand, one of them is the cherished "You do not pay
for stuff you do not use". People are choosing C++ for certain projects,
and very likely they have reasons. Any change of C++ should not invalidate
their reasons.

However, this is discussing generalities. Specific proposals for changes to
C++ can be discussed more rationally. In any case, changing C++ entails
taking a political approach. If you real objective is to have a good IDE,
then there is a clear engineering attack on that problem. A friend of mine
says that whenever you have a choice, the engineering way is more likely to
be successful. I find myself to agree with this more and more every day.

Stroustrup's treatmet of the goto was something on the order of. It's
there. There's little reason to ever use it.

Here's a bit of irony:
$ pwd
/usr/src/linux/kernel

Fri Jun 11 01:49:59:> grep goto *.c | wc -l
226

$ cd /download/edu/stanford/cweb

$ grep goto *.c | wc -l
37

$ grep Copyright README
% Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth


I enjoed Knuth's reading Knuth's treatment of the goto statement very much
when I read it. Personally, I think I have never used it in C++. But then
again, I started using for-loops about two months ago :-)
Best

Kai-Uwe
Jul 22 '05 #8

P: n/a
Kai-Uwe Bux wrote:
Hi,
Steven T. Hatton wrote:
I have to confess, I am a bit confused by all of this. If I have a
library with compiled code, I can use the declarations in the headers to
compile my source, and I don't need to know about the 'definitions' until
I call the
linker. Or so I believe. I am under the impression that what the
declarations provide me with are the names needed to communicate to the
linker what needs to be connected to what. So if the declarations in
your "fake" headers have "real" names in the form that the declarations
would appear, I don't understand why they would not suffice as real
headers to feed to the compiler.

As you can see, it contains way more information:

a) it gives away implementation details as it has to list private fields
and their types. b) it includes other headers, among them even those only needed in the
private part of the class.

The point that I hope to get across is that header files need to provide
information to the compiler that is of no concern to the programmer using
the library. Private fields of classes are of no concern whatsoever to the
user. Nonetheless, a compiler has to know about them at compile time.
Therefore, fake headers can not serve as sufficient information to the
compiler.
They don't need to. Stroustrups approach is very similar to what you are
doing. But he actually uses what you call a fake header. There is no rule
against having multiple declarations appear in the same translation unit.
I'm not really srue why header files that present things that aren't
necessary for the client's code should need to be #included in the client's
source file. They should be #included in your source files. What you are
calling the fake header should be #included in the client's source.
Stroustrup even #includes the equivilaent in the implementation's header to
test it for consistency.
There are more complicated examples involving templates, where it actually
can be usefull or even necessary to give implemting code in the header
files: after all template definitions need to be known at compile time. In
those cases, the header file will be cluttered with implemtation details.
A fake header will still be small and easy to read. But this is possible
precisely because it does not need to contain all the information that the
compiler needs to instanciate templates or allocate memory for private
fields in classes.
I'm pretty sure you can treat templates in much the same way as regular
source is treated. I'm still learning about templates, so there may be
significant exceptions to this.
Stroustrup clearly provides a notion of having two (or more) sets of
functional headers. One set might be accessed by the user of a
component,
while another would be accessed by its implementor. Perhaps I'm missing
something but it appears to me the Standard Library is not designed
according to the guidelines presented in TC++PL(SE).


I do not onw a copy of TC++PL(SE) so I cannot comment on this particular
assesment. However, why would it be necessary, better, or advisable that
the standard follows the guidlines in that book?


One reason is that the guidelines prescribe good programming practices.
Another reason is to maintain a consistent approach that will match the
reasonable expectations of people who learn C++ from the most authoritative
source available.
Interestingly the Standard says:

"A translation unit may include library headers in any order (_lex_).
Each may be included more than once, with no effect different from
being included exactly once, except that the effect of including
either <cassert> or <assert.h> depends each time on the lexically cur-
rent definition of NDEBUG.18)"

That seems to indicate that something is wrong with either the Standard,
or with the implementation.


Why? This requirement is probably met by most implementations. It just
states that


But the implementation I am discussing seems to be encountering problems
with this, so something must be wrong somewhere. I could be that I am not
fully understanding what they mean by circular dependencies.

I believe this reveals what I was saying about the failure of the
Standard Library to conform to the guidelines Stroustrup provides in
TC++PL(SE). There should be a user interface that hides such
implementation details. I have to ask what would go in my code to
correspond to these 'implementation_defined' types.


The typedefs in the standard make these types available to your code by
giving them names. These names are *the* means of using those
implementation_defined types in your code. What these types really are is
of no interest to the coder. (Of course, a compiler would have to know,
but that is the difference of header files and fake headers again. Again,
I think the standard provided fake headers, not header files.)


You are correct. I guess I have not fully adjusted to the notion of using
typedefs. I seems too much like forgery to me.
[fake headers] are entirely for my own inspection. See, my C++
coding style is still not very mature, and I actually prefer to not
declare but to define right away (sort of the Oberon style). Now, this
makes the interface hard to comprehend as code gets in the way.
Stroustrup presents (at least)two rather distinct notions of something
called an interface. One is that which I have described involving the use
of header files. The other is the use of abstract base classes as
interfaces.


I appologize for using the word interface. I will try hard not do that
again. I understand that it has become a loaden term in this discussion.


No. That wasn't my intent. I was merely observing that it is a bit
difficult to think about what is really meant by the term. I just came to
realize there seems to be a truly stunning irony in the extensive use of
non-implementing APIs backed by implementations in Java.

This is Stroustrup's design:
http://xml.apache.org/xerces2-j/java...es2/index.html

Too bad C++ programmers don't write code like that!
Oh, no. I'm not the expert. But my instincts tell me it's best to have
the interface representing the Standard Libraries created in conjunction
with the implementation, and indeed, they should be the source of the
declarations used by the compiler.


This seems to be the heart of the matter. As I pointed out already, the
compiler will need to know a lot more than I want to read in the standard.
I do not want the standard to tell me about private members of the
container classes.


You really should try to get a copy of Stroustrup's book. It explains how
both of these can be the case. That is, I get a foo.h user's header file
and the implementation has a foo_impl.h header file.

Moreover, if you "are not the expert", may I assume that you have some
experts on IDE design within reach? After all you seem to be highly
involved in this proect and there must be some people who would actually
try to code it. I am curious as to what they think on this matter.
The one person who would know best has been too busy to participate much. I
did notice he was back on the mailing list recently. Perhaps I should ask
again what he thinks. Much of the code has been written, and works with
many libraries.

But I have to say, the more I look at this situation, the more I realize
there is probably merit in the idea beyond it's applicability to IDEs.
To be
frank, it might be a little premature to ventilate changes to the standard
before actual engineering problems in designing an IDE prove those changes
useful. Your case will become a lot stronger once you can replace "my
instincts" with some concrete experiences illustrating which limitations
on IDE design are caused by shortcomings of the language.
Perhaps. OTOH, I do have a solid example from another programming language
that, as I've pointed out, seems in some ways to conform to Stroustrup's
guidelines than the C++ Standard does. With respect to changing a language, a good deal of conservatism seems to
be a very reasonable attitude. Certainly, I would approve of changes only
if they do not require serious rewriting of large portions of my code.
Moreover, there are certain underlying design goals that sort of govern
C++. As far as I understand, one of them is the cherished "You do not pay
for stuff you do not use". People are choosing C++ for certain projects,
and very likely they have reasons. Any change of C++ should not invalidate
their reasons.


Well, I know that one of my goals has a fairly well placed advocate. I want
to remove the "#" from C++.
--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
Jul 22 '05 #9

P: n/a
Hi,
These posts are getting a little too long, so I will focus on one point
only.

Steven T. Hatton wrote:
The point that I hope to get across is that header files need to provide
information to the compiler that is of no concern to the programmer using
the library. Private fields of classes are of no concern whatsoever to
the user. Nonetheless, a compiler has to know about them at compile time.
Therefore, fake headers can not serve as sufficient information to the
compiler.


They don't need to. Stroustrups approach is very similar to what you are
doing. But he actually uses what you call a fake header. There is no rule
against having multiple declarations appear in the same translation unit.
I'm not really srue why header files that present things that aren't
necessary for the client's code should need to be #included in the
client's
source file. They should be #included in your source files. What you are
calling the fake header should be #included in the client's source.
Stroustrup even #includes the equivilaent in the implementation's header
to test it for consistency.


and latter:
The compiler will need to know a lot more than I want to read in the
standard. I do not want the standard to tell me about private members of
the container classes.


You really should try to get a copy of Stroustrup's book. It explains how
both of these can be the case. That is, I get a foo.h user's header file
and the implementation has a foo_impl.h header file.

That appears to be an interesting concept. But you have me wonder how this
is possible. As you are refering to Java sometimes, let me describe, for
the sake of exposition, what, in my mind, is one of the major conceptual
differences between Java and C++: In Java all obects appear to be handles.
Consider the code:

a = b;
b.some_modifying_method( arg );

My understanding of Java is that the changes inflicted upon b will affect a
as well, after the assignment, a and b are names for the same object.
Whatever you do to it using one name you could as well do using the other.
In C++, this is not true--at least not for the compiler generated
assignment operator.

This difference is important for the ways compiler can go about generating
code. In Java any user defined class could always be represented by a
pointer. Assignment is pointer assignement. Since actual objects are only
created at runtime, it is the linker that must know about the sizes of the
physical objects that the object handles point to. But the compiler can
safely assume that an object handle has the size of one pointer. In C++,
life is more tricky. If the library presents a header:

// file: foo.h

class PhoneDirectory {
// private data fields suppressed.
public:

void insert ( const std::string & name,
const std::string & number );

...

}

and client code says:

// file: main.cc

#include <PhoneDirectory.h>

int main () {
PhoneDirectory dir;
...

}

Then, how is the compiler supposed to deduce the size of the variable
"dir"?
Best

Kai-Uwe

ps.: Please go gentle on me, I have only a very superficial knowledge of
Java, and what I said may grossly misrepresent Java.
Jul 22 '05 #10

P: n/a
Kai-Uwe Bux wrote:
You really should try to get a copy of Stroustrup's book. It explains
how
both of these can be the case. That is, I get a foo.h user's header file
and the implementation has a foo_impl.h header file.

That appears to be an interesting concept. But you have me wonder how this
is possible. As you are refering to Java sometimes, let me describe, for
the sake of exposition, what, in my mind, is one of the major conceptual
differences between Java and C++: In Java all obects appear to be handles.
Consider the code:

a = b;
b.some_modifying_method( arg );


Yes. Java's assignments are pointer assignments. You have to be more
explicit if you want a copy.
This difference is important for the ways compiler can go about generating
code. In Java any user defined class could always be represented by a
pointer. Assignment is pointer assignement. Since actual objects are only
created at runtime, it is the linker that must know about the sizes of the
physical objects that the object handles point to. But the compiler can
safely assume that an object handle has the size of one pointer. In C++,
life is more tricky. If the library presents a header:

// file: foo.h

class PhoneDirectory {
// private data fields suppressed.
public:

void insert ( const std::string & name,
const std::string & number );

...

}

and client code says:

// file: main.cc

#include <PhoneDirectory.h>

int main () {
PhoneDirectory dir;
...

}

Then, how is the compiler supposed to deduce the size of the variable
"dir"?


One answer is "don't do that". I've experimented with different approaches
to designing classes and found that putting variables instead of pointers
in classes can lead problems when working with headers. Unfortunately I've
found that when working with third party libraries it's not always possible
to have things my way.

This kind of thing presents a problem for me because I use certain design
approaches which rely on others. If for some reason I'm forced to violate
one of my established rules (or violate it accidentally), it often forces
another rule to be violated, or a behavior that I don't expect, because
I've forgotten all the consequences of violating the rule.

I am confident Stroustrup provides approaches for addressing the kind of
situation you have presented, but due to health reasons, I am not able to
focus on this right now. Part of the problem seems to point back to the use
of values rather than pointers in your class. I believe this is why what
are often called class declarations are technically definitions.
--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
Jul 22 '05 #11

P: n/a
Steven T. Hatton wrote:
Kai-Uwe Bux wrote:
You really should try to get a copy of Stroustrup's book. It explains
how
both of these can be the case. That is, I get a foo.h user's header
file and the implementation has a foo_impl.h header file.

That appears to be an interesting concept. But you have me wonder how
this is possible. As you are refering to Java sometimes, let me describe,
for the sake of exposition, what, in my mind, is one of the major
conceptual differences between Java and C++: In Java all obects appear to
be handles. Consider the code:

a = b;
b.some_modifying_method( arg );


Yes. Java's assignments are pointer assignments. You have to be more
explicit if you want a copy.
This difference is important for the ways compiler can go about
generating code. In Java any user defined class could always be
represented by a pointer. Assignment is pointer assignement. Since actual
objects are only created at runtime, it is the linker that must know
about the sizes of the physical objects that the object handles point to.
But the compiler can safely assume that an object handle has the size of
one pointer. In C++, life is more tricky. If the library presents a
header:

// file: foo.h

class PhoneDirectory {
// private data fields suppressed.
public:

void insert ( const std::string & name,
const std::string & number );

...

}

and client code says:

// file: main.cc

#include <PhoneDirectory.h>

int main () {
PhoneDirectory dir;
...

}

Then, how is the compiler supposed to deduce the size of the variable
"dir"?


One answer is "don't do that". I've experimented with different
approaches to designing classes and found that putting variables instead
of pointers
in classes can lead problems when working with headers. Unfortunately
I've found that when working with third party libraries it's not always
possible to have things my way.


I assume you understand that this proposal is way more radical than getting
rid of #. Macros are a minor concern compared to the using value semantics.
I am afraid, in this case, the answer "don't do that" is *not* an option.
As for me, the fact that C++ allows me to choose whether I want to use X or
X* is a *huge* plus of C++. Reserving objects of type X to the
implementation and have client code be restricted to the use of X* might
work for *some* projects where pointer semantics is a natural thing to
have. For most of my projects, value semantics in implementation *and*
client code is the right way to go.

Design approaches that work for you might not work for other people. C++
supports a variety of different programming styles and methods. Declaring
every language feature bad that is hard to reconcile with your ideal of
what headers ought to look like is a very peculiar way of going about the
problem.

I am confident Stroustrup provides approaches for addressing the kind of
situation you have presented, but due to health reasons, I am not able to
focus on this right now. Part of the problem seems to point back to the
use
of values rather than pointers in your class. I believe this is why what
are often called class declarations are technically definitions.


I am sorry to learn that you have health problems, and I hope you are
getting better so that we can discuss viable solutions soon.
Best regards

Kai-Uwe
Jul 22 '05 #12

This discussion thread is closed

Replies have been disabled for this discussion.