Hi,
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:
air< 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 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 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.
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