Slashdot Mirror


Abandoning Header Files?

garethw asks: "I'm working on a project where the lead developer, following a suggestion by our tool vendor, wants to get rid of the header files and directly #include source code. The language is a somewhat specialized language, but for all intents and purposes, you can assume it's Java or C. The conventional argument I recall for using header files, and incremental compilation, is that it's faster to use a makefile and conditionally build only those files that have changed. However, it turns out that the brute force of invoking the compiler once on the top-level does actually compile much faster. I feel that there is something about #include'ing source files directly, compiling only the top-level file, just doesn't 'feel' right and I'm at a loss to really give a solid argument as to why. Has anyone actually used this approach? Does anyone have any thoughts on any advantages or drawbacks?"

207 comments

  1. Need more info... by sfjoe · · Score: 4, Insightful

    ...following a suggestion by our tool vendor,...

    How much money will your tool vendor make if you implement this suggestion and what, if any, product does she sell that neatly solves any problems this might bring up?

    --
    It's simple: I demand prosecution for torture.
    1. Re:Need more info... by Jeremiah+Cornelius · · Score: 2, Funny

      i.e.: Will they pay for Dennis Ritchie's cardiac medication?

      --
      "Flyin' in just a sweet place,
      Never been known to fail..."
    2. Re:Need more info... by Anonymous Coward · · Score: 0

      i.e.: Will they pay for Dennis Ritchie's cardiac medication?

      More like "will they pay for your hospital bill when Dennis comes over and beats the crap out of you"

    3. Re:Need more info... by Tim+Browse · · Score: 4, Insightful

      If they're anything like some tool vendors I've come across, it's because they either don't have decent compilation perfomance, or don't support the features that would help, such as pre-compiled headers, etc.

      So rather than fixing the problem by investing in their product, they're telling their customers to use ugly hacks to get around the product's shortcomings, and hope they won't switch to another system (I suspect).

      I've certainly been on the receiving end of such tactics.

      The dead giveaway is when they start saying things like "pre-compiled headers wouldn't help you anyway" :-)

  2. Not useful for C by david.given · · Score: 4, Informative
    ...or, to a lesser extent C++, because of the way C scoping works:

    static global variables have scope within the module they're defined in. Which means that two static globals in different source files don't collide, because they're in different modules.

    Including everything into one big source file will mean that they're both in the same module, and so will collide. Not good.

    Can't say about other languages, though.

    1. Re:Not useful for C by Just+Some+Guy · · Score: 1
      You sure about that?
      $ cat inc1.h
      static int foo=5;
      $ cat inc2.h
      static int foo=10;
      $ cat test.c
      #include "inc1.h"
      #include "inc2.h"
      #include <stdio.h>

      int main() {
      printf("foo is %d\n", foo);
      return 0;
      }
      $ make test
      cc -O2 -pipe -fno-strict-aliasing -march=athlon-tbird test.c -o test
      In file included from test.c:2:
      inc2.h:1: error: redefinition of 'foo'
      inc1.h:1: error: previous definition of 'foo' was here
      *** Error code 1

      Stop in /tmp.
      Sticking the variables in separate files doesn't automatically get you namespace safety. Maybe you were thinking of Python?
      --
      Dewey, what part of this looks like authorities should be involved?
    2. Re:Not useful for C by angel'o'sphere · · Score: 2, Informative

      Lol,

      reread your parrent!!

      Exactly what you show is what he says. But he was talking about *.c Files, not *.h files. So while the *.c files would scope the foo variables leading to two distinct ones the +. h file pulls them both into the same c file.

      So what in the beginning worked, while it was scoped, does no longer work if everything is pulled int one single source file via #include.

      So your example exactly shows the conflict your parent wanted to point out.

      angel'o'sphere

      --
      Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
    3. Re:Not useful for C by stonecypher · · Score: 1

      Frankly, if you're using file-scoped variables, you should know better than to #include source. That said, file-scoped variables haven't been a good idea since 1980; even C programmers know better these days.

      --
      StoneCypher is Full of BS
    4. Re:Not useful for C by dusik · · Score: 1

      I think what david.given meant was that a static global variable has scope within the .C/.CPP file it's defined it (as opposed to the .H file). AFAIK, headers are sort of like plasmids which you then splice into the main strand of code via an #include. So, in your example, you were declaring the static foo twice in test.c by splicing those definitions in from the *.h files.

      Also, as far as I can tell, .h files are needed because you don't really control the order the .c/.cpp files are complied in. E.g., you may want to use an "extern" somewhere so the compiler doesn't freak out when it can't find something just yet. Also, they serve as a sort of table of contents.

      Ah... I think only a few people really have a clear understanding of precisely WHY header files are needed.

    5. Re:Not useful for C by ptomblin · · Score: 1

      file-scoped variables haven't been a good idea since 1980

      Yeah, now we use class static variables WHICH ARE THE SAME GOD-DAMNED THING, only with a pretty set of brace brackets around them.

      --
      The next Cmdr Taco duplicate will be ready soon, but subscribers can beat the rush and see it early!
    6. Re:Not useful for C by stonecypher · · Score: 1

      They certainly are not. File scoped variables aren't introduced into the external namespace. Besides, class statics should almost never exist; they are useful for shared buffering, singleton behavior, and little else.

      You shouldn't be abusing naming mechanisms, scoping mechanisms or generative mechanisms in order to isolate a variable from the outside world. Make a private member or a singleton instead.

      Also, please stop swearing when someone gives you constructive criticism.

      --
      StoneCypher is Full of BS
    7. Re:Not useful for C by Bloater · · Score: 2, Informative

      The term used in C is the "Translation Unit". When you compile a .c file you are compiling a translation unit. If the C source file #includes the contents of another file, then those contents replace the #include line in what the compiler considers to be the code to be translated.

      It doesn't matter what the file name is from the point of view of C, but a given compiler may use the last dot of the filename and the characters after it to determine which language it is, and whether it is a source file to be compiled or an object file to be linked.

  3. Interface vs implementation, shared libraries, etc by Dimwit · · Score: 3, Insightful

    Well, there's the obvious separation of interface from definition. And the problem of duplicate definitions - there's a reason why "extern" is a keyword. :)

    Plus, header files define an interface, which is useful if you don't actually have the code (i.e. binary shared library). Moot point in your case, I think, but...

    Plus it's just good programming style to have separate definitions and implementations. Easier to track down bugs.

    --
    ...but it's being eaten...by some...Linux or something...
  4. Re:Interface vs implementation, shared libraries, by Gherald · · Score: 1

    > it's just good programming style to have separate definitions and implementations. Easier to track down bugs.

    You can seperate definitions and implementations within 1 source file by using the following complex formula:

    1. Put the definitions at the top of the source file.
    2. Put the implementations at the bottom of the source file (i.e. after the defintions)

    This may be difficult to get used to at first, but once you learn how to use the Page Up and Page Down keys it's not so bad...

  5. Keep the header files by SunFan · · Score: 4, Insightful


    They are just about the only way to centrally organize declarations for data structures and function signatures. Doing so will save your ass eventually, because having function prototypes available can allow the compiler and lint tools catch stupid programmer errors. You do use lint-like tools, right? They _will_ catch bugs that testers and visual scanning wont.

    The only draw back to headers in C is that if you forget to 'make clean' after changing a header, you can end up with object files using old definitions. Just make a habit of doing a full build after changing the headers. If you designed your software properly, changing header files won't be all that common (adding functions new data structures, etc.).

    --
    -- Microsoft is the most expensive commodity operating system and office suite vendor in the marketplace.
    1. Re:Keep the header files by engywook · · Score: 1
      Doing a "make clean" should not be necessary, if you have constructed your Makefile properly.

      On the original question: I have never heard anyone I respected suggest the inclusion of executable source code. There is just too much peril.

      --
      "This signature quote intentionally left blank"
    2. Re:Keep the header files by SunFan · · Score: 1

      Doing a "make clean" should not be necessary, if you have constructed your Makefile properly.

      Agreed, but makefiles often are lazily maintained.

      --
      -- Microsoft is the most expensive commodity operating system and office suite vendor in the marketplace.
    3. Re:Keep the header files by CableModemSniper · · Score: 1

      what if object files are left out in the distribution froma compile on a different platform? Isn't that a reason to use make clean? I'm not trolling, I'm seriously asking, since I'm not really an expert on Makefiles (I can write simple ones).

      --
      Why not fork?
    4. Re:Keep the header files by Metaphorically · · Score: 1

      There could be a reason to make clean, but even in other cases, incorrect dependencies will eventually get you in any reasonably large project. If your dependencies are wrong, there are scripts out there (makedep or makemake) for making dependency information.

      --
      more of the same on Twitter.
    5. Re:Keep the header files by fenris_23 · · Score: 1
      You do use lint-like tools, right? They _will_ catch bugs that testers and visual scanning wont.

      Is that what those errors mean everytime I check in files? :-P

    6. Re:Keep the header files by engywook · · Score: 1

      I would recommend structuring your build tree and makefiles in such a way that build products for different platforms are placed into (or built into) different directories. Thus, each platform's build products are kept distinct, and no make cleans are required.

      --
      "This signature quote intentionally left blank"
    7. Re:Keep the header files by Rumata · · Score: 1
      if you forget to 'make clean' after changing a header, you can end up with object files using old definitions


      You need better dependency handling.
    8. Re:Keep the header files by Anonymous Coward · · Score: 0

      There's nothing to maintain, all you need to do is: gcc -MM `find . -name \*.c` > Makefile.MM; echo "include Makefile.MM" >> Makefile
      tada.wav, you can make the dependency generation part of your "autogen" script if you use one, or "make distclean", or use any other better method if you dare looking at some big-momma Makefiles, which try to do it every run of make (we need it only after new file is added to the project - maybe use a script adding file.o to the Makefile and `gcc -MM file.c` to the our Makefile.MM).

    9. Re:Keep the header files by Froggert · · Score: 1

      engywook is correct, and any reasonable build system will already be doing this. I work in a team that builds binaries for ~11 different CPU types, and we consume binaries and build systems from numerous other teams. All of them use some form of $(OutputDir) = $(Platform incl. CPU)\$(Configuration e.g. Debug, Release, etc.)

      --
      What, me worry?
  6. Speed by jbrandon · · Score: 3, Insightful

    Have you tested the speed difference when you change only one non-header file? I bet incremental compilation will make that quite a bit faster. In addition, if you want to compile that changed source file to check for syntax or type errors, you don't have to check for collision between it and the whole rest of the project, only collisions between it and the header defining it.

    1. Re:Speed by stonecypher · · Score: 2, Insightful

      I bet incremental compilation will make that quite a bit faster.

      Chances are he's got massive coupling problems, which can totally throw away any benefit of incremental linking. And by the way, incremental compilation is something totally different; whereas I realize that the error is that of the original speaker, not yours, it should nonetheless be pointed out.

      C++ does not support incremental compilation, though ICC and MSVC both have extensions to support it. MSVC refers to it as runtime code generation: you change the source, MSVC swaps out a vtbl, and the new compiled piece of source is literally injected into a running program.

      TU seperation is incremental linking, not incremental compilation.

      --
      StoneCypher is Full of BS
  7. GCC by lexarius · · Score: 2, Interesting

    My OS prof was demonstrating the differences in what errors the C compiler and linker would pick up. However, we found that we could make two source files with no include lines in either that both defined a global variable (sans extern). The main function set the global variable and then called a function that is defined in the other source file, which would then print the gv. Then we compiled and linked them with gcc. No warnings, no errors. The program ran exactly the way we wanted it to, which was unexpected. So yes, you can do away with includes and header files without even performing the includes manually. Depending on the language, your compiler might be smart enough to figure it out.
    But that doesn't make it a good idea. Besides, do you want to be the one who has to go update the library functions that would normally have been included any time you change the code in one file?

    1. Re:GCC by Jamie+Lokier · · Score: 2, Informative

      That's not an error, and if your OS prof said it was an error that was not picked up, he/she is mistaken.

      The C language definition is clear that you can write the program you did, with a variable defined in "common" form (no initialiser and no extern) in both files, and a function called without a prototype, and it is a valid C program with well defined behaviour.

      -- Jamie

    2. Re:GCC by lexarius · · Score: 1

      Out of curiosity, where can I find this? Was it added to a recent version of the definition? He seemed to be under the impression that this functionality had been added to gcc for programmer convenience and wasn't standard behavior. After all, compilers weren't always smart enough to not need function prototypes or explicit includes.

    3. Re:GCC by bikiniAtoll · · Score: 1

      Function prototypes were a feature added to C when it became an ANSI standard to help avoid errors. The behaviour you are seeing is certainly normal - that is the way things would have worked back in the K&R days.

    4. Re:GCC by Jamie+Lokier · · Score: 1

      The functionality is much older than GCC, and even pre-dates the first ANSI C specification. Any ancient (i.e. 1970s onwards) unix C compiler will behave like this. In the old days (K&R C, before ANSI/ISO C), there were no function prototypes.

      -- Jamie

    5. Re:GCC by Anonymous Coward · · Score: 0

      If you declare the same variable with "static" in each file, then each will have its own copy. If you declare it "extern" then it will be not be defined locally, and the linker will not link the objects unless one of the objects has it declared. If you declare it without "static" or "extern" then you're not working with a private copy of the variable, any other variables within the same scope and of the same name will all be lumped together, and anything defined as extern will be linked to the defined variable.

  8. Incremental compilation by marcovje · · Score: 1

    I think the separate header is simply code duplication and memory limitations of old C compilers.

    Larger programs (compilation unit) could be compiled if the preprocessor - compiler were separated, and used batch processing, unused parts of the headers were never seen by the compiler.

    The main problem with headers is that preprocessor stat is global to the entire operation, not per header or C file.

    This makes conditional state flow from one to the other, which makes separate precompiled headers hard (since the conditionals might not match).

    Also the header system requires manual making of makefiles (or using quite complex scanners and tools) , while this could be easily done by a compiler fairly easily. See most Wirthian languages (e.g. Turbo Pascal vs Turbo C++) for examples.

    1. Re:Incremental compilation by marcovje · · Score: 1

      _Avoid_ code duplication of course.

      Also note the speed of e.g. Turbo Pascal or Delphi.
      It stems mostly from not having to cope with recursively included headers.

      If a unit is imported for the second time, they can simply copy the state, since preprocessor state has no effect on the precompiled header. The compiler only has to resolve recursive
      inclusions.

      Header caching _is_ possible for C though; make could keep the compiler alive, and have e.g. a CRC over the conditional state, to see if the state changed.

    2. Re:Incremental compilation by crmartin · · Score: 1
      No, it's a limitation of the C language that was imposed by the old compilers' environments'.

      Remember that in The Old Days, the C compiler had to run each phase in less than 64K 16-bit words, text and data. Separate compilation allowed the separate segments to be compiled within those limits, and then the .o files could be linked as a last step. This also allowed for such niceties as overlaying loaders etc.

      #include was a mechanism to eliminate code duplication; instead of recoding the interfaces in each module, you could use the preprocessor to let you bring in the definitions once.

      Languages like Pascal, that depended on compiling everything all in one lump had serious memory limitations that limited the size of the programs badly.

    3. Re:Incremental compilation by WolfWithoutAClause · · Score: 1
      Not entirely.

      One thing I've noticed is that the automatic recompilation feature of Java seems broken- changing a file doesn't reliably trigger recompilation of all affected .class files. That's really bad for big projects since you basically have to recompile everything from scratch.

      I've never quite got to the bottom of how and why, but I beleive that if Java had automatically generated separate header files and code files and dependency lists from the .java files then it probably would have worked correctly, since the compile could check the date on the header file and only recompile code files that need recompilation- much like C does (on a good day with decent tools, which alas are rare).

      --

      -WolfWithoutAClause

      "Gravity is only a theory, not a fact!"
    4. Re:Incremental compilation by aled · · Score: 1

      I don't remember if Sun's javac compiler does dependency checking but others like IBM's Jikes does . Using an Ant build script may do it for you for free.
      I think you are wrong on that using header files would make it better. Just doing the check on the source .java and the generated .class works without introducing redundancy and creating less files to compile. C compilers don't do dependency checking, most of the time you must set it in makefiles or your IDE, and with makefiles it's usually a by hand work, nothing elegant to see there. What modern C compilers usually do is to avoid recompiling headers, a kludge that is needed by the use of including files that's ineficient in the first place. Java does it much better IMHO.

      --

      "I think this line is mostly filler"
    5. Re:Incremental compilation by WolfWithoutAClause · · Score: 1
      Yeah but Gcc for example spits out the dependency information if you ask it to, and then you can suck that into a makefile automatically. Then the makefile only needs to check the timestamp on the files to know whether it needs to rebuild everything and nothing that doesn't. I think I benchmarked that at 10,000 files in 45 seconds plus compilation time.

      Java's compiling technique seems to me to be quite broken- only recompiling the .java files that have changed often results in runtime problems. If you're lucky it will be an error otherwise it will just do something strange. I'm not sure whether ant has a fix for that; it's theoretically possible, but I don't know it well enough; I doubt it. I think the clearcase tool can do this properly with Java, because it watches the files that the compiler opens. But the last place I worked didn't set it up properly and they just recompiled everything every time.

      --

      -WolfWithoutAClause

      "Gravity is only a theory, not a fact!"
    6. Re:Incremental compilation by aled · · Score: 1

      Gcc for example spits out the dependency information if you ask it to, and then you can suck that into a makefile automatically.

      Gcc does that but it is a kludge to me because you are expected to maintain it by yourself or include it on the makefile. This is the kind of thing that should be automatic, without you having to setup the dependency data.

      Java's compiling technique seems to me to be quite broken

      I don't agree with you. First, this is not a problem with Java but a limitation of some tools, notably the javac compiler from Sun. In some cases it may not possible to detect all dependencies if you use dynamic loading of classes, but that is a feature and one should be aware of its limitations before using it.
      Ant has a depend task that deletes older classes. It uses the dependency information stored in the class file : "The depend task works by determining which classes are out of date with respect to their source and then removing the class files of any other classes which depend on the out-of-date classes.

      To determine the class dependencies, the depend task analyses the class files of all class files passed to it. Depend does not parse your source code in any way but relies upon the class references encoded into the class files by the compiler. This is generally faster than parsing the Java source."
      Then a pass from the compiler will generate all missing class files. You can find the details at the Ant manual, search for javac and depend tasks.
      Just watching the files opened is dangerous because Java can generate multiple .class file per source because of inner classe (example: a.java can generate a.class, a$1.class, a$2.class, etc). The tool may miss something.

      --

      "I think this line is mostly filler"
    7. Re:Incremental compilation by stonecypher · · Score: 1

      I think the separate header is simply code duplication and memory limitations of old C compilers.

      Headers have never had anything to do with memory limitations, and by definition code in a header cannot be repeated in an implementation file. It's worth noting that code should only ever be in a header if it is to be inlined, which doesn't exist in C until C99, by which point memory limitations simply don't matter. (It is worth pointing out that placing templates in headers is not placing code in headers, but rather placing code factories in headers, which is quite a different thing.)

      Larger programs (compilation unit)

      The phrase "compilation unit" does not mean anything in C++. I expect you mean Translation Unit, but TUs aren't a function of larger programs; it's simply that in larger programs not seperating your code into TUs is suicide. A translation unit is simply the code block associated with an object file (or other prelinker binary.)

      The main problem with headers is that preprocessor stat is global to the entire operation, not per header or C file.

      This is not a problem; it is an asset. Without preprocessor effects spanning the compile tree, virtually every metaprogramming technique and virtually every compile-time code removal not built on SFINAE would simply fail.

      This makes conditional state flow from one to the other, which makes separate precompiled headers hard (since the conditionals might not match).

      State does not exist in the compile tree. This is a critical misunderstanding of the way in which a compiler works - the preprocessor effectively does not exist within the code tree. There is no state whatsoever; that would imply that during either compilation or runtime the preprocessor's effects could be altered, which simply isn't true. There is a good explanation in Modern C++ Design of the limitations which statelessness imposes on metaprogramming techniques in C++, and how one can avoid them by other means such as typelists. As far as making seperate PCH hard, well, it's not really hard in any way. There's no issue of conditionals matching, because since the preprocessor is stateless, there is no way to ordinate a conditional. (There are arguments that metaprogramming techniques like Substitution Failure Is Not An Error defeats this; they are wrong. SFINAE is a compile-time polymorphism, not a conditional; no branch is ever taken.)

      Also the header system requires manual making of makefiles (or using quite complex scanners and tools)

      Uh, no it doesn't. Here's a rudimentary generic makefile. It would be wise not to discuss limitations of tools with which you are not familiar. Besides, the idea that something like NMake is complex is sort of funny; it's actually quite retarded. Back in reality, it's the languages which implicitly generate header-type interface definitions which need complex scanners, which are built into the compilers themselves; that's probably why you remain unaware of them.

      See most Wirthian languages (e.g. Turbo Pascal vs Turbo C++) for examples.

      Wirth has nothing to do with Turbo Pascal, which is an instance of (depending on the year) either Borland Pascal or Object Pascal. This is a bit like calling C++ a Kernighan language. Object Pascal and Borland Pascal are both significantly distant from ANSI Pascal, the closest non-dead relative to the original teaching tool.

      Namedropping doesn't make you seem correct, y'know.

      --
      StoneCypher is Full of BS
    8. Re:Incremental compilation by marcovje · · Score: 1

      I had a whole reply ready, but IMHO it is not worth the trouble replying to. Maybe it is better when you read the original post with some comments.

      Oh, and:

      you>Namedropping doesn't make you seem correct, y'know.

      Neither does getting personal about perceived faults, when it's pretty much your own assumptions that are the problem.

      -------------------

      Reread the original msg with this in mind:
      - I never said _anything_ about C++. Neither does the thread starter. I assume roughly some C like language, non in particular. So the whole template rant is bogus.

      - When I am talking about state, I'm talking about state in the compiler. (which in most _performing_ tools has the preprocessor built in btw) There is more than just the code trees in a serious compiler, specially when it can do whole programs in a run. E.g. state about precompiled headers. For something serious to make header systems peroformant, the compiler needs access to the preprocessor internal state anyway, to decide if a header needs reevaluation.
      - The pascal angle is mostly to illustrate a system that depends less on the "simply inline" header system. The philosophic differences between C and Pascal languages are large, but the basic principle is that there are two ways of including foreigh code:
      -- by {$i} ({$include in delphi), like #include in C
      -- by uses, which invokes the unit system.

      The main reason, and the fundament of a unit system, why the second way is more optimal than headers, is that the compiler reinitialises before reading a unit interface. IOW the preprocessor symbols from the program that USES don't affect the unit, and the decision about recompiling the unit is easy. Load the precompiled header from the compiled unit (if it is not already in the unit cache), and let's go on with it.

      Any way to speed up C headers should keep this in mind:
      - either preserve the state of the preprocessor (defined symbols etc) before entering a header.
      - or add a flag to header or compiler cmdline to signal that headers are not allowed to change.

      Of course, saying "pascal" to most C(++) users is equivalent to waving a red cloth to a bull, but contrary to the bull case, that is not my problem.

    9. Re:Incremental compilation by WolfWithoutAClause · · Score: 1
      Just watching the files opened is dangerous because Java can generate multiple .class file per source because of inner classe (example: a.java can generate a.class, a$1.class, a$2.class, etc). The tool may miss something.

      Actually, no, because in order to write the files out the compiler must have opened them. The clearcase technique is very clever and general. Still, Ant seems pretty good from what you say.

      --

      -WolfWithoutAClause

      "Gravity is only a theory, not a fact!"
    10. Re:Incremental compilation by stonecypher · · Score: 2, Informative

      I had a whole reply ready, but IMHO it is not worth the trouble replying to.

      "Oh, I wrote a reply, but I don't want to paste it because you're not a good person and I don't want to." My eight year old son knows that nobody falls for this sort of passive agressive dismissal; it's disappointing that you do not.

      Namedropping doesn't make you seem correct, y'know.

      Neither does getting personal about perceived faults, when it's pretty much your own assumptions that are the problem.


      Observing that something you've done isn't effective is hardly my getting personal. Believe me, there's no shortage of material; what I said above about my son is, for example, personal, as is the following: turn down the whine knob until you've got something worth saying to say.

      So the whole template rant is bogus.

      Given that it was not you but the original poster which set the domain of important languages, and given that I also touch on pure-C and pure-Java issues, this protest is as bogus as it pretends what it's attacking to be.

      - When I am talking about state, I'm talking about state in the compiler. (which in most _performing_ tools has the preprocessor built in btw)

      Yes, I heard you the first time. The reason I referred you to modern c++ design is that you're wrong, and I have neither the patience nor the kindness to explain it to you. Start with section 3.5, or with any page explaining how C++ template metaprogramming is a functional language rather than an imperative language. Before you fly off the handle talking about how you weren't referring to templates *again*, please realize that the observations regarding template MP as a functional language in fact apply to everytihng in the C and C++ preprocessors.

      Do not reply until you have read; repeating ignorance is no more argument than repeating falsehoods.

      -- by {$i} ({$include in delphi), like #include in C

      Actually, you're shooting yourself in the foot here. You're attempting to make the hasty generalization that there are two approaches to bringing outside code into a local place, that C/C++ advocate an "inline header system" (whatever the hell that is) and that Delphi does something different.

      What you seem to fail to understand is that uses is a call to the Delphi linker; it is literally the same thing as the linker in C++, and in fact if you take the time to look at borland's BPIL, you'll find that they generate the exact same intermediate language binary. Furthermore, the very same examples you give, {$i} and {{$include}}, are the same as #include. Furthermore, both languages offer still other mechanisms to bring code in or to generate code.

      That said, talking about Pascal's differences with C and then discussing what Delphi does is roughly equivalent to describing what Objective C does. Delphi is not pascal any more than Objective C is C. They are distinct languages. Delphi is Borland's third pascal variant, Object Pascal, which follows both Borland Pascal and Token Pascal (the last of which is so old that you pretty much can't find references to it online.)

      Please don't lecture to me about Pascal; my use of Pascal predates Borland's very existence.

      The main reason, and the fundament of a unit system, why the second way is more optimal than headers, is that the compiler reinitialises before reading a unit interface.

      Uh. The pascal unit system is simply an in-code linking mechanism. It's no different than rolling your source together with your makefiles; if you'd bothered to read Wirth's papers on the design of the language you'd find out that Wirth himself suggests that "unit" is nothing important, and pretty much just syntactic sugar.

      Now, how the compiler "reinitializes" before reading a unit interface is a little bit beyond me: the unit interface is just what a C++ programmer would call a collection of vtbls. Would you be willing to point me to any point

      --
      StoneCypher is Full of BS
    11. Re:Incremental compilation by marcovje · · Score: 1

      [i]I suspect you're probably trying to discuss DCUs, but that would be a faulty analogy; the parallel to DCUs are compiled libraries (*.o, *.lib, etc depending on platform,) not uncompiled libraries, and as such the issue of recompilation is a non-issue. [/i]

      They are both (interface(read: compiled header)+implementation(as in code)) You can have a program importing units. The compiler will load the interface in symbolic form from the DCU, and compile the main program.

      Only the linker, takes the compiled program and the implementation part from the .dcu. (or .tpu)

      [i]Because Pascal doesn't have headers, [/i]

      The interface part of the unit more or less is. At least according to the definition. I'm used to.

      If you really want to make a point, try to explain something instead of just flame arrogantly. I'm not native english, and not very well versed in C(C++) jargon, but arrogancy won't help to fix that language barrier.

      [i]it also doesn't have precompiled headers.
      Do you not realize that there is a major distinction between precompiled headers and vtbls?[/i]

      I don't know what a vtbls in your definition is, or how it relates to the discussion. I assume object vtables, but I don't get what you are hinting at.

      [i]Uh. Headers can't change, no matter what. They never carry anything which changes. Do bear in mind that both inlined code and templates are injected into implementations, where any changing occurs.[/i]

      What I was hinting at:

      simply a commandline override variatn of the manual avoidance of the C header. So to avoid having to code the workaround you show with test1 and test2.

      What I could also state:

      If you have a mutual dependancy in units, you can resolve it by compiling the mutual units twice.
      E.g. A import B and B imports A, both in interface.

      The first compile simply has to determine size, the second compile has the other units types, and adds the typeinfo.

      (compiler reinitialisation)

      In the BP case you have a main program that compiles A and B.

      Compiler starts compiling main program, but then decides to do A. Above the USES statement, already preprocessor symbols can be defined. This state doesn't go over to when you are compiling the unit. It is not a real reinitialisation of course, since it just swaps to a different namespace for the unit.

      Maybe I should have said preprocessor state per compilation unit, and not reinit compiler.

    12. Re:Incremental compilation by WolfWithoutAClause · · Score: 1
      Oh, yeah, I forgot- there's one annoying difference between Java and C/C++.

      In Java if you modify the code of in a class method, if everything works perfectly [which it never seems to :-) ] it triggers recompilation of all the dependent classes- even though they don't actually need recompilation.

      In C/C++, modifying the .c or .cc file only triggers recompilation of the .o file and relinking.

      That can make an *enormous* difference on a big system- and modification of code without modifying the header file is very common. On a mature system that can save >>50% of compiling.

      I don't think *any* of the Java toolsets deal with that issue.

      If the Java system wrote out the 'header' separately from the code then before replacing the header file after recompiling the .java it could check to see if it had really changed, if it hadn't it could leave it alone; and that would preclude it doing unnecessary work.

      --

      -WolfWithoutAClause

      "Gravity is only a theory, not a fact!"
  9. Why? by Pacifix · · Score: 4, Insightful

    It seems that the onus should be on the vendor to explain very, very convincingly why you should abandon decades of standard practice and good coding practice. This better be one hell of a good product you're developing to justify the should a radical change. You shouldn't need to defend standard practice, they must campaign for a change to that practice. Imagine trying to explain this to all the coders who will work on the product for the next decade - will they think you're crazy or is there really a reason to do this?

    1. Re:Why? by CamMac · · Score: 5, Funny

      Remeber, if you remove all the comments from the code, it will compile faster and the executable will be smaller.

      --Cam

      --
      All jocks think about is sports. All nerds think about is sex.
    2. Re:Why? by crmartin · · Score: 1, Informative

      Someone should mod this either "funny" or "dumb".

      (In real compiled languages, the comments are stripped out in lexing or earlier. In C, they're stripped by the preprocessor.)

    3. Re:Why? by MerlynEmrys67 · · Score: 1
      Well, I agree with the first, but pray to god every day that the second is true (However I will agrue it IS true in interpreted languages)

      Now why is this ? Simple lets make a bastard case - you have 10K of code and 10M of comments. Obviously if you don't have to read the comments off of the disk - it will take less time (and one of the limitations in performance I have seen in compilation is raw disk speed). Now in interpreted languages - the whole source file is read - leading to longer startup costs ( but after the interpretation - similar code should be generated leading to similar execution speed)

      --
      I have mod points and I am not afraid to use them
    4. Re:Why? by aled · · Score: 1

      For starters it will be even better if you remove all whitespace and tabs. For more advance examples of better practices of C programming learned over decades of good coding take a look here.

      --

      "I think this line is mostly filler"
    5. Re:Why? by gl4ss · · Score: 1

      you would run most such interpreted languages through a obfuscator(even if you didn't want to obfuscate) if size or code reading speed mattered. or if you were savvy and cared.

      (with j2me, obfuscators are regularly used this way - to reduce the size of class files even if they're pretty understandable after the obfuscation when looked with a decompiler at)

      --
      world was created 5 seconds before this post as it is.
    6. Re:Why? by stonecypher · · Score: 1

      In real compiled languages, the comments are stripped out in lexing or earlier

      Yes, that's the joke.

      In C, they're stripped by the preprocessor.

      No, they aren't. They're stripped by the tokeniser. There are a number of neat tricks in GotW which rely on this distinction.

      --
      StoneCypher is Full of BS
    7. Re:Why? by crmartin · · Score: 1

      Implementations differ, as usual, but I promise you that many C preprocessors do this. Um, I know for sure that it did in 11/70 UNIX C.

      But what do you want for stone knives and bearskins.

    8. Re:Why? by endx7 · · Score: 1

      No, they aren't. They're stripped by the tokeniser. There are a number of neat tricks in GotW which rely on this distinction.

      You can't rely on that distinction. AFAIK, no standard says where the comments get lost. With gcc, they will get stripped out by the preprocessor. I ran cpp, gcc's preprocessor, to find this out for sure, although it's entirely possible that the actual compiler portion may understand to strip them out as well.

      Other compilers may differ.

    9. Re:Why? by sharkey · · Score: 1
      Remeber, if you remove all the comments from the code,

      Remember, if you remove some letters from words, your comment will parse faster, and be almost as readable.

      --

      --
      "Outlook not so good." That magic 8-ball knows everything! I'll ask about Exchange Server next.
    10. Re:Why? by stonecypher · · Score: 1

      I've just tested. GCC, BCC, ICC, Arm ADS, Arm SDT, CodeWarrior, MSVC 7.1 and GHOC don't. I don't have my copy of MetaWare High C anymore, but I bet it doesn't either. Can you provide an example of a compiler which is c89 or later which does?

      I am reluctant to believe that GotW tricks are based on things which cannot be relied upon.

      --
      StoneCypher is Full of BS
    11. Re:Why? by AuMatar · · Score: 1

      If you have a "trick" that depends on the compiler doing things in a certain order, you shouldn't be relying on it, period.

      --
      I still have more fans than freaks. WTF is wrong with you people?
    12. Re:Why? by crmartin · · Score: 1

      Son, when you've been doing this for 40 years, you'll have trouble keeping chronologies straight too.

      The specific example of a system in which I think this was a problem was Bell Labs UNIX running on a PDP 11/45 in about 1979. But for all I know, it could have been anything from VMS 3 VAX C (probably not, actually, since the memory architecture didn't work that way) to Tiny C on a Cromemco S100 bus system.

    13. Re:Why? by stonecypher · · Score: 1

      I didn't ask you for a chronology, nor in fact for the condescention, only an example of a compiler which exhibits the behavior you suggest. Given that you're not certain of what compiler it was, and given that both VAX C and TinyC were known to have significant faults in standards compliance, I fear that you're confusing personal experience with low quality software for standard behavior, or perhaps even just misremembering.

      I will ask you again. This is not a request for a chronology, nor is it a request for you to tell me you've been programming for 40 years in a question regarding a language which isn't yet 30 years old. This is a simple, straightforward question.

      Can you provide an example of a c89 or better compiler which exhibits the behavior you suggest?

      --
      StoneCypher is Full of BS
    14. Re:Why? by crmartin · · Score: 1

      That's okay, the condescention[sic] was lagniappe.

      So which behavior is it we're talking about? The business about the CPP phase stripping comments is certainly correct, viz:


      1000 $ cat foo.c
      /* foo.c -- a comment */
      #define ACONST 42

      static int foo(){ /* another comment */
      return ACONST ;
      }

      int bar(){
      return foo();
      }
      1001 $ gcc -E foo.c
      # 1 "foo.c"
      # 1 ""
      # 1 ""
      # 1 "foo.c"

      static int foo(){

      return 42 ;
      }

      int bar(){
      return foo();
      }
      1002 $


      If we're talking about the business about the TEXT and DATA segments, since standards are your big deal here, can you cite anything in the ANSI standard that says the TEXT segments must be combined as you suggest?

      And if not, wouldn't you think that it would be foolish to make assumptions about how it would behave?

      Some years ago, I did some work for DARPA on trustworthy C compilation, and one of the things we discovered was that there are LOTS of places where you can't make assumptions about the standard just because it was what you were used to.

      As far as "significant faults in standards compliance", look at the dates I'm talking about, son. C89 was a 1989 standard, and I'm talking about 1979. Those compilers didn't fail to comply with the standard in 1979-84 because it would be five years before the standard was promulgated.

      In this business, 1979 << 1989.

    15. Re:Why? by GreyArtist · · Score: 1

      I always love to here that old, tired argument (not): We should stick with the way we've always done things because that's the way we've always done it.

      Modules for a 7 million line coding project are probably an average of 50,000 lines each at a minimum (who wants to keep track of more than 140 modules). Yet modules for a 50,000 line coding project will be drastically smaller. No one ever came up with overriding standards for how big a module should be and the limits of what it should accomplish. Depending on the project, demodularization may make perfect sense or it might be utterly ridiculous. The true error occurs when new, more efficient methods are overlooked merely for the sake of doing it the same old way its always been done.

    16. Re:Why? by Anonymous Coward · · Score: 0

      As far as "significant faults in standards compliance", look at the dates I'm talking about, son. C89 was a 1989 standard, and I'm talking about 1979.

      D'ont be too hard, young people have the false 'need' to pretend to know simply too much.

      Yes, I am being condescendent, son. :)

    17. Re:Why? by Anonymous Coward · · Score: 0

      I recommend using machine code. Compile speed is second to none.

    18. Re:Why? by crmartin · · Score: 1

      I think part of the point is that including all the code through the preprocessor is an old, dumb way of doing it. Not a new trick.

      By the way, another one of those "old fart" comments is coming, brace yourselves: ... actually, you'll almost always find that modules in a 7 megaSLOC program are much the same size as in a 50KSLOC project, and if that means you have 7000 modules, then you do. A "module" has to be of a size to be comprehended by one person.

      A really big forest doesn't generally have really big trees.

    19. Re:Why? by GreyArtist · · Score: 1

      My point was that forests of any size are made up of trees of different sizes (admittedly I may not have used the best analogy). Sometimes it might make sense to have a single, large tree out in the middle of nowhere. Finding the best solution possible means finding the best solution possible, it doesn't mean blindly following the advice of someone who's only rationalization is "that's the way its done." My experience (as an old fart) lets me know that anyone who tries to sell you that line is the last one you should be listening to.

    20. Re:Why? by stonecypher · · Score: 1

      condescention[sic]

      Look it up, Brainiac. That's how it's spelled. You know, the noun conjugation of condescend.

      That's okay, the condescention[sic] was lagniappe.

      Lagniappe is a noun. Why are you attempting to use it as an adjective? (I won't even bother explaining to you what a Lagniappe is; you wouldn't believe me. Just take it on faith that even if you had used correct grammar, you'd still be out in left field.)

      I note that you're still totally unable to answer my simple question: can you or can you not provide me an example of a c89 compiler which strips comments in the lexer? GotW is smarter than either of us; they're quite correct, and until you show me a c89 or better compiler which behaves otherwise, you're remaining on the clueless peg.

      That's three messages in a row you've written a whole tirade without answering the question. Doesn't it embarrass you to be this pathetically obviously evasive?

      If we're talking about the business about the TEXT and DATA segments, since standards are your big deal here, can you cite anything in the ANSI standard that says the TEXT segments must be combined as you suggest?

      I never suggested any such thing, and TEXT and DATA have nothing do do with at what point in the compilation the comments are removed. You're just making things up.

      By the way, C doesn't actually specify that there are TEXT and DATA segments at all; that's a Unix convention. C doesn't even require a lnkscript. When you get into embedded programming you'll maybe find this out. This reminds me of those people which insist bytes are eight bits, etc.

      Some years ago, I did some work for DARPA on trustworthy C compilation

      I don't believe you. Luckily, since I actually do have such ties, it's relatively easy for me to look people up. What was the project number, and what was your project UID? It won't give me your name; the entire purpose of a UID is to allow you to safely identify your work without identifying yourself.

      You really shouldn't lie about things like this; eventually you'll bump into somoene which really does secure government contracting, and they'll ask you for procedural details which you cannot provide. I'm sure, though, that you'll either ignore the question or pretend there's no such thing as a work UID.

      and one of the things we discovered was that there are LOTS of places where you can't make assumptions about the standard just because it was what you were used to.

      Oh man, this makes my head hurt. You can't make any assumptions about a document which puts things into concrete terms? That doesn't make any sense. How could you possibly assume a part of a standards document? Either it's there or it isn't.

      I haven't made any assumptions; you've made dozens, and ignored my requests for reference. Make this sort of handwavery all you want; you're transparently clueless.

      As far as "significant faults in standards compliance", look at the dates I'm talking about, son. C89 was a 1989 standard, and I'm talking about 1979. Those compilers didn't fail to comply with the standard in 1979-84 because it would be five years before the standard was promulgated.

      (sigh)

      As any experienced C programmer knows, there were virtually no standards-compiliant C compilers before c89. The issue is not whether the C compiler adheres to the 1989 standard; the issue is whether the C compiler is new enough to be standards compliant at all. Again, I remind you that the standard is in strict defiance of your claims, and that all you have to do is either show me a passage in the standard which supports you or a compiler which supports you.

      Make all the excuses about the examples I'm requesting being ill targeted that you like; the burden of proof is on you, not me, and you've been evading that burden as hard as you can.

      Even one example would do. Do you have one?

      In this business, 1979

      This is too stupid to mock.

      --
      StoneCypher is Full of BS
    21. Re:Why? by crmartin · · Score: 1

      condescention[sic]

      Look it up, Brainiac. That's how it's spelled. You know, the noun conjugation of condescend [m-w.com].


      's', not 't'. 'Condescension'. Try your spelling at M-W and see what you get. And 'lagniappe' is idiomatic for "thrown in for free", like the 13th donut in a baker's dozen.

      As any experienced C programmer knows, there were virtually no standards-compiliant C compilers before c89.

      Look, you dolt, there were no standards-compliant C compilers before C89 because THERE WERE NO STANDARDS. Get it?

      In the mean time, let's see: you've asserted that comments are removed by a C compiler's tokenizer, not the preprocessor, which is easily demonstrated wrong, and you've asserted that BY THE STANDARD text segments of C object files are merged into the same text segment at load time, but when challenged to cite the spec, you're complained about me pointing out your spelling mistakes.

      Nice flaming with you, son, but there's a blow-out rule, and as we're running about 427-0 right now, I think maybe you should just change your name and hope to live it down.

  10. Several advantages and disadvantages by cookd · · Score: 3, Insightful
    1. Advantages:
    2. Faster compile of the full product. You only invoke the compiler process once, and much less work for the linker to do.
    3. Much better optimization. Compilers can only optimize within a compilation unit. Intel and Microsoft have "Link-time code generation" compilers which performs a final optimization pass during link, but if you aren't using those compilers, there might be a significant amount of additional optimization enabled by putting everything in the same compilation unit.
    1. Disadvantages:
    2. You're not doing it the way everyone expects you to do it. Certain components (the compiler, the linker, and pre-existing code) might have been designed under the assumption that individual files would be compiled separately. The pre-existing code might have declared static (per-file) variables or functions in a way that could collide with other code (namespaces might help here). The compiler and linker might have limits. And you might not hit those limits until late in the project.
    3. For building the whole product, yeah, it will be faster. But for making a small change and rebuilding the results of that change, it might be much slower.
    As with every issue you'll ever run into, there are two (or three) sides to it.
    --
    Time flies like an arrow. Fruit flies like a banana.
    1. Re:Several advantages and disadvantages by marcovje · · Score: 1


      You can accomplish (1) by letting make keep the compiler alive, and only call some init.

      I also agree with (2), and a simple example is inlining small calls across compilation units.

      IMHO the best solution would be to allow tighter integration between make - cpp - gcc - as - ld

      4 binaries to run per compilation unit is quite a lot of overhead. (ld runs for the bin only). This would push up memory requirements a bit though.

      Caching headers in-compiler/preprocessor would then also be possible.

      If this was done, it should be mainly done as an optional mode for the "current" target, and allow the old ways for crosscompiling/bootstrapping purposes.

    2. Re:Several advantages and disadvantages by mugnyte · · Score: 1

      >>You're not doing it the way everyone expects you to do it.

      Let's extend this: Developer churn. Software lifecycle. Is this lead developer going to write a full documentment explaining (1) the easy stuff: the compilation steps AND (2) the minutae of hacks, fixes and workaround when you hit compiler limits, newb misunderstandings, etc.

      Think about your way slower compile when only a single module changes implementation. abandon static libs and your make time should be swift.

      Overall I think you could solve the problem by choosing a different language than a C-based h/c combo change. If you go that route, do as the Romans.

    3. Re:Several advantages and disadvantages by Anonymous Coward · · Score: 0

      Faster compile of the full product.

      So for a 10 second speed up you'll get multiple year's worth of maintaince headaches!

      This is the one night stand of comp sci.

    4. Re:Several advantages and disadvantages by stonecypher · · Score: 4, Informative

      1. Faster compile of the full product.

      Well, back in the real world, in a properly decoupled project incremental linking is a massive speed win, even when building from the top, as there's far less cross-lexing and as the build tables may be handled a small piece at a time, which is important because their parsing in the compiler itself is generally of O(n^2 log n) time or better. Once you've worked on a large project which fails to make proper decouplings, you will become painfully aware of this trend.

      Whereas in this particular project the complete build is apparently faster, that is almost certainly the result of a very naive code tree and/or build scheme; the importance of incremental linking towards speed of compile cannot be overestimated, even in the case of compiling from clean.

      2. Much better optimization. Compilers can only optimize within a compilation unit.

      This simply isn't true. Whereas only some compilers make cross-TU optimizations, that is not the same as cross-TU optimizations being only able to optimize within a translation unit (why do people keep saying compilation unit? There's no such thing!) Besides, you're dramatically underestimating the commonality of link-time cross-tu counterspecialization, which now exists in ICC, BCC, MSCC, ARM ADS, EDG/Comeau, GHOC, and is in experimental development within GCC.

      You're not doing it the way everyone expects you to do it. Certain components (the compiler, the linker, and pre-existing code) might have been designed under the assumption that individual files would be compiled separately.

      They most certainly have not been. The C and C++ standards do not allow for such ridiculously inappropriate behavior. Where did you get this idea? Compiler writers may not impose arbitrary restrictions on the codebase in any relation to the local filesystem. This is just untrue.

      The pre-existing code might have declared static (per-file) variables or functions in a way that could collide with other code (namespaces might help here).

      This is a well known gigantic red flag indicating an amateur programmer. File-scoped variables are antiquated even within the pure C community; the only time they're acceptable in most professional programmer's eyes are within a library which is built alone. In fact, you might want to read the things Kernighan himself said about when file-scoped variables are appropriate in K&R 2; the primary author of the language himself says that this is a fundamentally bad technique and should not be done.

      Of course, that you're causing problems by misusing the toolchain and allowing bad code to collide when build trees written seperately are blindly merged without the help of a linker is just not surprising.

      The compiler and linker might have limits.

      Not if they're standards compliant, they mightn't. Did you know that there's a document out there floating around telling compiler authors in concrete detail what they may and may not do? You should read that before commenting on what a compiler may or may not do; you are simply out in left field, here.

      As with every issue you'll ever run into, there are two (or three) sides to it.

      Not when you know what you're talking about. Whereas many things are issues of pro/con, many simply aren't; you'll be hard pressed to find pros in the distribution of heavy ordinance to delusional sociopaths, you'll be hard pressed to find pros in setting up a "bring a molester to school day," and you'll be hard pressed to find pros in non-decoupled code, once you've actually read the standard and are aware of the real limitations of compiler authors, instead of your guesses about what might maybe happen if someone wasn't paying attention.

      --
      StoneCypher is Full of BS
    5. Re:Several advantages and disadvantages by dourk · · Score: 1

      Wow, man, you sound really smart. I'm impressed.

      --
      Wake up.
    6. Re:Several advantages and disadvantages by stonecypher · · Score: 1

      From someone whose URL involves the word "guru," almost certainly without having earned it, to attack a set of reasoned arguments with underpinnings with a nasty comment about appearances is just pathetically self-ignorant.

      --
      StoneCypher is Full of BS
    7. Re:Several advantages and disadvantages by dourk · · Score: 1

      Actually, I did think he sounded smart. I was impressed.

      I'm sorry you thought I was being insincere. Apparenty, offering a compliment is bad form on /.

      And no, I'm not new here.

      --
      Wake up.
    8. Re:Several advantages and disadvantages by stonecypher · · Score: 1

      Oh, my. I apologize: the way that was phrased, I had taken it as sarcasm.

      --
      StoneCypher is Full of BS
    9. Re:Several advantages and disadvantages by crmartin · · Score: 1

      I think you're having a little difficulty with a couple of real-world issues here (not to mention the one about "keeping a civil tongue", but this is slashdot.)

      First of all, you're losing context: we're not talking about an actual C++ program compiling on a current-generation compiler, we're talking about someone's weird-ass C-like language compiled on some very peculiar implementation. We're not sure what the peculiarities are, other than knowing that startup time for the compiler must be awe-inspiringly bad.

      Given that, and given the arcane nature of optimization in production compilers, the one thing we can bet on is that the optimization is not as smart as some. You're making an unwarranted assumption there, not to mention your assumptions about the implementation of the compiler, linker, etc.

      Second, when someone tells me "that doesn't matter because no 'good' programmer would do it that way", I know I'm talking to someone who hasn't got a lot of actual real-world experience. If the specific semantics of the language allow something, some dfamn fool's gonna try it.

      Sometimes the damn fool will be a real smart one: for example, Steve Bourne's version of sh was written with a collection of #define macros to make C's syntax look like Algol60. In other words, the code looked like

      IF(x == NULL) THEN
      y = 2* z;
      ELSE
      y = z * z ;
      FI

      Steve is no dummy, and I'm sure it seemed like A Good Idea At The Time.

      In this case, you're arguing that only amateur C programmers use file scope. That's a clear sign of someone who thinks C++ is C. You're completely right that there's no reason to use file scope in a C++ program: you've got everything from static const to namespaces to eliminate the need (and nearly eliminate the need for the preprocessor as well.)

      IN straight C, however, file and static are one of the few things you have to manage the namespace in larger programs. Whether or not your particular religious version of "good coding practices" allows for them is unimportant, as there are undoubtedly legacies of code using that in the tens of billions of lines.

      And as far as using file scope making me an "amateur", from your tone and your arguments, I suspect I'd been a professional programmer for 25 years the day you were born.

    10. Re:Several advantages and disadvantages by kelnos · · Score: 1
      This is a well known gigantic red flag indicating an amateur programmer. File-scoped variables are antiquated even within the pure C community; the only time they're acceptable in most professional programmer's eyes are within a library which is built alone.
      Uh, excuse me? To which community are you referring? You sound to me that you've done very little in the way of real-world programming. Using file-scoped variables (not to mention file-scoped functions, which also have the potential for conflicts in this scenario) can be very useful and make things easier. Of course, care must be taken if you're working in, e.g., a multithreaded environment. But to say that file-scoped variables are "antiquated" just shows a level of real-world ignorance on par with an academic. Either that, or someone who works mostly with C++ and is trying to speak about something with which he knows very little.
      --
      Xfce: Lighter than some, heavier than others. Just right.
    11. Re:Several advantages and disadvantages by dourk · · Score: 1

      Gotcha!

      --
      Wake up.
    12. Re:Several advantages and disadvantages by Anonymous Coward · · Score: 0

      I'm sorry you thought I was being insincere. Apparenty, offering a compliment is bad form on /.

      It's certainly uncommon. Next time say something besides "dude, you're awesome, I love you!!!" and perhaps it won't be mistaken as sarcasm.

    13. Re:Several advantages and disadvantages by GreyArtist · · Score: 1

      First, let me say I mostly agree with the other criticisms that have been levied against your statements. You seem to be mainly arguing that the most modern software practices are the correct ones mainly because they are modern (and because they are yours).

      Second, the limits of the compiler and linker that were referred to originally are most likely hardware or hardware-like limitations (i.e. a PocketPC versus a Gaming PC). The document you referred to would not address implementation-specific limitations like these.

      Third, I am not sure why any of you are talking about incremental linking. Incremental linking can be used to reduce fixups of memory address references when linking a single module as well as multiple modules. The root forum message is talking about demodularizing the project (using one object code module for the entire project). I think you are getting the term incremental linking confused with this modularity.

      I personally think the most convincing argument for decoupling (modularizing) code is code reuse, using the module for more than one project or for more than one version of a product. With or without this reuse, compile time and link time seem very trivial concerns to be arguing about, especially in the modern hardware age.

    14. Re:Several advantages and disadvantages by Anonymous Coward · · Score: 0

      I'm not surprised he came to the wrong conclusion. The sentence makes more sense if it is sarcasm. He truly did go out of his way to make himself sound smart, a trend I am noticing with his earlier posts. I'm sure he realizes the truth to this, even if he wont admit it and instead flames me, which if he reads this post is inevitable.

  11. unclear on what you mean by Dink+Paisy · · Score: 2, Interesting
    You need to clarify exactly what is going on... My best effort at interpretation is that currently you have something like:

    gcc -c f1.c gcc -c f2.c gcc -c f3.c gcc -o f f1.o f2.o f3.o

    Your vendor instead thinks it would be better to do:

    gcc -o f f.c

    Where f.c looks like:

    #include "f1.c"
    #include "f2.c"
    #include "f3.c"

    Am I right, or am I completely off track?

    If I'm right, you'd probably still want to include header files because you want everything to remain modular. According to software engineering type people, that makes maintenance easier. Another problem is symbol scoping. C keeps symbols local to the module they appear in, so you want to make sure you have naming conventions, namespaces, or some other protection against naming clashes. I'm dubious about the benefits, but I work on projects that take significant amounts of time to compile. Not hours, but enough time that if you wait for all the objects to compile you are wasting a lot of time. In general, I'd claim that the larger the project, the worse an idea it is.

    --

    Whoever corrects a mocker invites insult;
    whoever rebukes a wicked man incurs abuse.
    --Proverbs 9:7
    1. Re:unclear on what you mean by stonecypher · · Score: 1

      If I'm right, you'd probably still want to include header files because you want everything to remain modular. According to software engineering type people, that makes maintenance easier.

      Whereas you understand the original petitioner's complaint correctly, including headers in a project which simply mass-merges all the source would have absolutely no effect on modularity. The modularity which developers are probably referring to with regards to headers is the ability to swap out libraries without recompiling client code (though fragile linking in both C and C++ make this a relatively difficult problem without handles or visitors, hence COM and CORBA.)

      C keeps symbols local to the module they appear in, so you want to make sure you have naming conventions, namespaces, or some other protection against naming clashes.

      C doesn't have namespaces or modules. Locality to a translation unit, which is not the same thing as a module (experience in Clean or Objective C will clear the distinction right up,) is not guaranteed; it is explicitly in the control of the author by way of the "extern" keyword. This is an observation of C's default behavior, not its only behavior; similarly, functions may return things other than int, may accept arguments other than varargs, and may have variables whose construction time isn't auto.

      --
      StoneCypher is Full of BS
  12. Time you gain, you loose in debugging by StarWynd · · Score: 2, Insightful

    While including code directly may speed up the compilation time, you will loose all the time you gain and then some when you get into debugging.

    If you have a complicated #include chain, you can wind up with a lot of duplication. Some compilers will complain, some won't. However, if you have typedefs, structs or the like, most compliers will complain and not compile your code until the duplications are removed. I don't know what compiler you're using or if you are planning on including more than functions or global variables, so I don't know if this is an issue or not.

    The more general issue is that it's much easier to track down bugs and other problems if there is a clean separation between definitions and implementations. I can't characterize that difference in a few sentences, so I'll just say that it has been my experience that projects which are developed in a true modular nature are much easier to debug than projects designed in a monolithic nature. The time saved in debugging more than makes up for a little time lost in compilation.

    1. Re:Time you gain, you loose in debugging by stonecypher · · Score: 2, Insightful

      If you have a complicated #include chain, you can wind up with a lot of duplication. Some compilers will complain, some won't.

      So sorry: the ODR rule prevents duplicated code from functioning in any compliant C or C++ compiler, all the way back to day one (and in fact into the parent languages B and BCPL.) This is simply false.

      However, if you have typedefs, structs or the like, most compliers will complain and not compile your code until the duplications are removed.

      If by most you mean all...

      so I'll just say that it has been my experience that projects which are developed in a true modular nature are much easier to debug than projects designed in a monolithic nature.

      Uh. Modularity and monolithism are not related. Modularity is the design technique of seperated interface definition such that one may swap in alternate implementations of code, such as through TUs, polymorphism, SFINAE or various metaprogramming techniques. One may contrast structured programming, functional programming, lambda calculus or contract substitution.

      Monolithism is a development model: designing all at once and then implementing top-down from start to finish. Constrast the waterfall model, iterative development, chain development, and so on.

      The time saved in debugging more than makes up for a little time lost in compilation.

      Right on: preach it, brother. This is one of the least understood principles of modern design: machine time is significantly inferior to programmer time. Herb Brooks would be proud.

      (No, I'm not being sarcastic. Yes, I did just compliment you heavily after criticism.)

      --
      StoneCypher is Full of BS
    2. Re:Time you gain, you loose in debugging by humblecoder · · Score: 1, Informative


      Right on: preach it, brother. This is one of the least understood principles of modern design: machine time is significantly inferior to programmer time. Herb Brooks would be proud.


      For those who don't know, Herb Brooks is the lesser known brother of famed author Fred Brooks. Herb is best known for writing the obsure tome, _The Legendary Monkey-Hour_. LMH is not as well known as older brother Fred's _Mythical Man Month_, but among primate coders, it is the bible.

      Herb is also the President of the Billy Einstein Appreciation Society, a group dedicated to studying the work of the oft-forgotten sibling of Albert Einstein, who penned the Theory of Absolutitivity.

    3. Re:Time you gain, you loose in debugging by Anonymous Coward · · Score: 0

      LMAO!!!!!

      I'm not sure which is funnier though, the parent's post or the +3 Informative mod it's got right now.

      Excellent work Humblecoder, your humor has not gone unnoticed.


    4. Re:Time you gain, you loose in debugging by stonecypher · · Score: 0

      huhuhuhuhuhu. sorry, it was five in the morning and i'd been talking about sutter a lot. my mistake.

      --
      StoneCypher is Full of BS
  13. Another question by SunFan · · Score: 1


    If you put all your source code into the compiler at once, what about memory usage? Sometimes, I've seen g++, for example, go crazy on an otherwise normal source file. I really don't know enough to know why.

    --
    -- Microsoft is the most expensive commodity operating system and office suite vendor in the marketplace.
    1. Re:Another question by endx7 · · Score: 1

      Optimization is one reason. If you turn optimization off, gcc's memory usage is a lot more reasonable. I had gcc consume so much memory optimizing once that I had to turn optimizing off or all (swap and real) memory would get used up and gcc would abort. This was an pretty old machine and pre-gcc 3.x.

  14. Depends on the size of the project by nadador · · Score: 2, Informative

    Depending on the size of your project, you will get varying returns from each of these:

    1. Seperate source files means that units of code can hide data and functions.
    2. Seperate headers, combined with something like GCC's -Wmissing-prototypes enforces the good coding practice of well defined functional interfaces.
    3. Seperate headers and source files means that when you look at a function in a file, you will have some idea of what it touches because you can go and look that it included header X but not Y.
    4. You can tell the compiler to explicitly forbid global data symbols, which is pointless in one single file.
    5. You can use different compiler switches for different files.
    6. Your code will have some hope of portability.

    If your project is small, it doesn't matter anyway. If your project is large, you can get your compiler to enforce some good design rules on you, which doesn't mean you can't still have a good design anyway, but it will make it more likely. I worked on a project that used a compiler that let you get away with everything. Try and port that code to anything UNIX-like, and it was ridiculous.

    --

    Outside of a dog, a book is a man's best friend. Inside a dog, its too dark to read.
  15. It can work by Anonymous Coward · · Score: 0

    For a few years I worked in Modula-2. One of the interesting things about it is that the language has include built in as a first-class concept.

    Normally, one file contains one module. A module is pretty similar to a class in that it's an encapsulation structure. Each module has an interface and body/implementation part, each of which are coded. This is very similar to a prototype in a header.

    Whenever code in one module references code in another, the module starts with a series of imports. An import reads the interface.

    There are a few nice things about this scheme; linking doesn't require a make file because all the information for linking is contained in the code; and the compiler can be smart - when an interface hasn't changed but the implementation has changed, only a recompile of that module is required, and a relink; when an interface changes, the compiler knows what the impact is and need only recompile those implementations that are affected.

    Before I used the system, I thought it would be slow. However, it was FAST. I think there were several reasons:
    - Modula-2 is a well designed language so compiling is fast.
    - The compiler can be aware of what must be compiled.
    - The linking process is smart.

    Between then and now, C++ has gained all these capabilities, so there's no reason to think that C++ hasn't gained in the same way.

    I think it's a better and smarter system than separate header and body files, which were a hack to gain this advantage. And modern compiler technology supports it.

    1. Re:It can work by marcovje · · Score: 1


      IMHO the crucial question is (and I can't answer it,
      don't know C++ that well): Does in C++ preprocessor state flow from header to header?

      In Modula2/(Turbo)Pascal you can simply check filedate (and compute file crc if you want to), and if it is the same, you can assume your precompiled header is ok, since no other _code_ can influence it.

      Of course commandline params can, therefore, the precompiled header also contains a struct with the parameters with the header was compiled, and you can check if that is equivalent.

      In Turbo Pascal, you also have to do recursive header detangling, but I don't know if recursive inclusions in the header are allowed in std Modula2. (in TP they are, but must be resolved after one mutual recompile)

    2. Re:It can work by stonecypher · · Score: 1

      Between then and now, C++ has gained all these capabilities, so there's no reason to think that C++ hasn't gained in the same way.

      Actually, the BCPL family has this as far back as B; K&R C had incremental linking from day one, and is a year older than Modula-2 (1978 and 1979, respectively.) That said, the BCPL family did not invent it either; this technique was in practice in Wirth's original Pascal tool in 1970, and may stretch further back than that (in fact, probably does: I'm looking at an early-era Pascal tutorial which lists the benefits of the new language, and that isn't among them despite the huge impact it would have had on machines of the day, suggesting someone else had it first, though I'll be damned if I can think of who.)

      I think it's a better and smarter system than separate header and body files, which were a hack to gain this advantage.

      Disagreed strongly. Headers have much more far-reaching impacts than Modula's modularization system; consider for example that Modula requires all source to be present at compile time, whereas C only requires that the headers be present. This is a significant design advantage, and as a side effect also allows the distribution of binary libraries, something which Modula-2 does not support. Those two reasons were the basis of inventing headers; they are a better tool, not a hack.

      And modern compiler technology supports it.

      Also ancient.

      --
      StoneCypher is Full of BS
    3. Re:It can work by stonecypher · · Score: 1

      Including all the source code into one main file compiled to one object can work, if the source files cooperate. C can have problems with the namespace, but C++ allows multiple namespaces and you can even put the namespace blocks in the main file around the #includes.

      Surely you're joking? Do you actually fail to understand how broken such a behavior would be? Consider the relatively trivial case of a #included file which contained two namespaces, and attempted to reference one another through uses clauses. This is a blatant CFAD behavior.

      The source code has to support this, though.

      This sentence alone is enough warning that any experienced programmer would be cluebulbing right now.

      C can have problems with the namespace

      C doesn't offer namespaces.

      I've done this on lots of projects and it works great.

      Er. Then you had just as many massive coupling problems as the original author appears to. #including source is the wrongest of the novice linking mistakes, and whereas that's a total zealot thing to say, I don't care, because it's also true. You would do well to read up on the basics before giving out any more bad advice.

      or an appeal to tradition

      Actually, many of the posts have been about how easy it is to introduce errors this way (such as your namespace abomination above.) That said, the reason most of the posts are about speed is because the poster was asking about speed. "Hey, this car magazine talks about cars too much."

      Modern compilers will create pre-compiled headers that can include code, usually used for template and inline definitions

      Templates aren't code, and inlined code doesn't go into precompiled headers (in fact it cannot, for obvious reasons.)

      Actually, even larger projects seem to take longer to link with iostream and windows.h than the source does to compile.

      Linking should be virtually instantaneous; it's a question of copying a tiny bit of binary code and setting a pointer at the beginning of a vtbl. If your linking of iostreams or windows.h is taking a visible amount of time, then there's something very wrong with your compiler, or you're making some bizarre mistake which I've never seen (given what you said above, that doesn't seem terribly unlikely.)

      Too much inlining will cause code bloat, but the compiler's options should give you control over the balance.

      If you had read the standard, then you would know that inline is a hint, not a requirement, much like register. In fact, the language specifies that the programmer cannot control inlining, and that inlining is totally the compiler's decision. If your compiler listens to you, that's because it's being nice, not because you told it to.

      Modern compilers also allow you to change the compilation options mid-file.

      No they most certainly do not. I suspect you're referring to #pragmas within the source; a real C programmer knows that #pragmas are not C, but rather an explicit backdoor introduced by ISO during standardization. The focus of C and C++ was originally and remains to this day that of portability; #pragma is the work of the devil and should never, ever occur in code. This should begin to give you minor cluebulb about why real programmers are frustrated with MSVC; see also _tmain, main(int, char*, char*), void main(), et cetera.

      Any debugger or source analyzer shouldn't have problems handling inline or same-file implementations, or you're using bad tools.

      Debuggers and source analyzers do not act on the precompiled source. Rather they act on inserted tokens in the binary, which are given references to source locations. By definition a debugger cannot be affected by inclusion. You seem not to understand many of the tools which you are attempting to discuss.

      It can also be easier

      --
      StoneCypher is Full of BS
    4. Re:It can work by Foolhardy · · Score: 1

      Surely you're joking? Do you actually fail to understand how broken such a behavior would be? Consider the relatively trivial case of a #included file which contained two namespaces, and attempted to reference one another through uses clauses. This is a blatant CFAD behavior.

      I've done it plenty of times before. I've even put #included files inside a template struct using a type parameter for what would have been a typedef, then using different types. I've never had to reference the global namespace, but if this was a problem, defines would be a good workaround.

      The source code has to support this, though.

      This sentence alone is enough warning that any experienced programmer would be cluebulbing right now.

      This goes for any style of writing code. The source has to be written to support declaritive header files if you want to use those. Any piece of code has to be written to support the things you want it to. Anything can be abused if you don't use it correctly.

      C doesn't offer namespaces.

      C doesn't offer multiple namespaces but does have a single namespace, where all the names go. I specifically said singular namespace, wich C does have.

      Then you had just as many massive coupling problems as the original author appears to. #including source is the wrongest of the novice linking mistakes, and whereas that's a total zealot thing to say, I don't care, because it's also true. You would do well to read up on the basics before giving out any more bad advice.

      That page tells you in two different places to use headers as always but provides exactly zero reasons as to why.

      You say there would be coupling issues; have you actually done this in a project? Maybe you just don't know how to use this technique correctly? There are masses of things than are powerful but can be abused if you don't know what you are doing. To make them safe, there are rules and constraints that need to be followed, just like there are in using pointers or kernel programming.

      Templates aren't code, and inlined code doesn't go into precompiled headers (in fact it cannot, for obvious reasons.)

      If it isn't code, then what is it? Just what is your definition of code, anyways? No, it won't be converted into ML until the parameters have been supplied, but so what? You also can't compile something until you've selected a target architecture. Does that mean it's not code unless it has the CPU type embedded? It's a piece of information that's missing before it can be compiled.
      When somebody says "for the obvious reasons" it usually means they really don't know but for whatever reason believe it anyway. State the obvious reasons. If template code can go into them, what's to stop non-template code?

      If you had read the standard, then you would know that inline is a hint, not a requirement, much like register. In fact, the language specifies that the programmer cannot control inlining, and that inlining is totally the compiler's decision. If your compiler listens to you, that's because it's being nice, not because you told it to.

      So? How is this in conflict with what I said? In the real world, compilers give you some control over inlining and how you use it will affect the code's performance; something you should be aware of.

      No they most certainly do not. I suspect you're referring to #pragmas within the source; a real C programmer knows that #pragmas are not C, but rather an explicit backdoor introduced by ISO during standardization. The focus of C and C++ was originally and remains to this day that of portability; #pragma is the work of the devil and should never, ever occur in code. This should begin to give you minor cluebulb about why real programmers are frustrated with MSVC; see also _tmain, main(int, char*, char*), void main(), et cetera.

      I said that modern comp

  16. Re:Are you stupid? by Profane+MuthaFucka · · Score: 1

    I can understand why you got modded down, but honestly, this is the question that occurred to me as well. There's a great many polite and informative responses here, but when you get right down to it, I think you nailed it.

    --
    Fascism trolls keeping me up every night. When I starts a preachin', he HITS ME WITH HIS REICH!
  17. Never thought we'd need to explain the obvious by Lord+Kano · · Score: 2, Interesting

    You have issues with scope.

    The easist one for me is that with #includes, it's so much easier to fix bugs. If you find a bug or an inefficient way to solve a problem, you only have to fix it once. Everything that #includes the suspect file will be fixed on the next compile.

    If customfunctions.h has been changed or optimized, you don't have to edit the 30 projects that you're using those functions in. Just the one file is fixed, each project gets the benefits during the next compile.

    LK

    --
    "Hi. This is my friend, Jack Shit, and you don't know him." - Lord Kano
    1. Re:Never thought we'd need to explain the obvious by garethw · · Score: 1

      But the same applies to their method.

      The individual source files don't all have function prototypes of the classes or functions in other files. Those file themselves are #include'd, so they end up being all in the same translation unit (if that's the correct term).

      --
      garethw
  18. Off the top of my head... by Dormann · · Score: 2, Interesting
    Playing devil's advocate to most of the replies I've read so far, there are two benefits you could get from this approach.

    If your language supports "static" in the file-scope sense, you could declare every global object as static and reap the compiler optimizations that come with that declaration.

    If your language supports smart inlining, you could end up with code that has been inlined more effectively, since any code could be an inlining candidate regardless of location.

    I can think of plenty of reasons to back away from the idea, but they'll flood in here without my help.

    1. Re:Off the top of my head... by crmartin · · Score: 1

      I don't think the "static" advantage is all that big an advantage when you consider a large program. Remember the semantics of static are different from the semantics of auto, and depending on some code generation issues, of extern.

    2. Re:Off the top of my head... by Dormann · · Score: 1
      I would imagine a large program to reap many tiny benefits from that adjustment.

      A compiler can consider a variable with file scope to be never extern. Meaning that the usage of that variable is completely covered in the current compilation unit.

      With that info, a compiler could decide to make a variable an inlined constant if its value is never modified. Or more frequently, the variable could be aliased or cached since the compiler would always know external function calls are never going to modify it.

    3. Re:Off the top of my head... by stonecypher · · Score: 1

      If your language supports "static" in the file-scope sense, you could declare every global object as static and reap the compiler optimizations that come with that declaration.

      Er. There are no optimizations which apply to globals but not to globals. No, that's not a typo: file-scoped variables are globals whose names are not imported into the external tokenspace. There is no difference from the perspective of the compiler between the two; file-scoping is a purely lexing issue, and lexing cannot optimize in any way.

      If your language supports smart inlining, you could end up with code that has been inlined more effectively, since any code could be an inlining candidate regardless of location.

      Once upon a time, people were admonished not to use string and vector because various compilers didn't implement them correctly. Then, it was exceptions. Then, it was template specialization. Currently it's exportation and template template arguments (yes, that word should be repeated.)

      Programmers which have been around for more than a few years generally hold the same opinion: to hobble your code based on certain compilers being behind is short sighted. Within a year or two all major compilers will be doing the right thing, and in the meantime you've already got the code correctly. Whereas it's a clear case of Ad Verecundiam, I still want to point out that Meyers, Dewhurst, Sutter, Vlissides and Alexandrescu have all spoken strongly against this opinion.

      --
      StoneCypher is Full of BS
    4. Re:Off the top of my head... by crmartin · · Score: 1

      "Thanks, half-pint. You've just saved me a lot of investigative work."

      Yeah, that's a good point. I knew there was something, but I couldn't think of an example.

    5. Re:Off the top of my head... by topham · · Score: 1


      At one time it did make a difference. File-scoped variables were handled via pointer references, while true globals were handled as far pointers. (actually making true globals less efficient.)

      course those were the days of segmentation, and all the enjoyable things that resulted in.

  19. Interesting solution by Anonymous Coward · · Score: 0

    Your solution seems interesting, if somewhat unconventional. But what is the problem you are trying to solve with it?

  20. ccache by yamla · · Score: 3, Informative

    It is hard to tell from your statements, but this may stop tools like ccache from working. I use ccache in my projects and it radically cuts down the amount of recompilation required when I do a complete rebuild. Now, an obvious question is why I don't simply rely on makefiles to ensure only changed files ever get rebuilt. This often happens because compilation involves generating new cpp files that are then compiled and I don't want to be grepping through these all the time. I suppose I could move them all to a different directory, but ccache works very well.

    The other problem, of course, is that separating your classes into header and implementation means that if you change the implementation, you only need to recompile that one file and relink, rather than recompiling EVERYTHING. This can be a matter of a few seconds vs. several minutes. And implementation does change, a lot... fix a bug, you fix the implementation. The headers change too, but much much less frequently.

    --

    Oceania has always been at war with Eastasia.
    1. Re:ccache by stonecypher · · Score: 1

      The other problem, of course, is that separating your classes into header and implementation means that if you change the implementation, you only need to recompile that one file and relink, rather than recompiling EVERYTHING

      Of course, his original post explicitly deals with this issue, and rejects your opinion out of hand; if you want to tell him about this, you need to help him understand why it isn't working for him. It is frequent for non-mediocre programmers to fail to understand the problems of mediocre programmers; I hereby suggest that you are not stupid enough to grasp the real problem here. It is my guess that he's got major coupling issues, and that any invokation of the compiler ends up revisiting all source files, whether or not they were actually touched.

      This can be a matter of a few seconds vs. several minutes.

      In the case of Starcraft, it's the difference between 30 seconds and several hours. In the case of Windows NT, it's the difference between a few minutes and two weeks.

      --
      StoneCypher is Full of BS
    2. Re:ccache by Anonymous Coward · · Score: 0

      Why not use a different extension for the generated cpp files?

      Or, use a seperate directory for you output files?

  21. Re:Interface vs implementation, shared libraries, by Unordained · · Score: 1

    Sadly, that doesn't work so well for template classes. I understand why, but it's still unfortunate that you can't separate template declarations from their definitions -- as it is, the code winds up being somewhat messy and hard to read, and if you care about such things (I don't for our in-house software) you can't "hide" the implementation of your code.

    I know for our newer programmers, it's hard to read through a messy .h file to see what's "available" -- and that's always the problem when learning a new language or environment, isn't it? You need to know what's there for you to use, so you don't reinvent the wheel -- good header files do that for you.

    It takes me over an hour to build our project, when I have to. We have to build more often that I'd like because several years ago we screwed up some interfaces such that our originally-separate libraries and our main app are somewhat locked together (cross-referencing #include) -- it can be fixed, it'd just take time (and we don't have a good tool to hunt down the dependencies we want to rid ourselves of.) Just changing one of a few files affects everything, even if it shouldn't in theory (that is, if I had been in my right mind.) In our case at least, there's a clear advantage when we don't build the project, but only a subset (over an hour vs. a couple minutes, including linking) Maybe if you only have a *few* source files ... but when you've got hundreds?

    Besides, you don't always have the source. Eventually, you start having to rely on interfaces to get what you want anyway. Might as well stick with good habits and separate implementation from interface. Eh.

  22. Use #includes sparingly? by mattgreen · · Score: 2, Interesting

    When I write libraries, I try to make them header-only. Generally users don't want to have to modify their makefiles if they don't have to, and I'll resort to compiler specific pragmas if I have to.

    It depends on the size of the system. If you are using a component-based system then only the pieces of the system that are actually being modified should be compiling anyway, which cuts out a lot of compilation. However this implies there is fairly loose coupling involved. In a more conventional application, there has to be a breaking point where the amount of time to parse files is longer than the time to link them normally. Using precompiled headers on any system header will also drastically decrease the time it takes to compile, since the compiler essentially just dumps the parse tree out to disk. So much time is spent inside some system headers! (Especially Windows.h. Ugh!)

    There are some tools that keep the header files in sync with source files automatically, but I don't know of any off-hand. I have seen some for C, but I'm not sure there is one for C++ that supports all the wild and crazy stuff like namespaces and templates. :)

    1. Re:Use #includes sparingly? by stonecypher · · Score: 1

      I find it incredibly disappointing that this post, which seems to be the only actually clueful post in the discussion, has had no moderator points applied to it. I would do it myself, except that I'm crusading around splitting hairs.

      Please mod parent up: he's not only correct, but absolutely dead-on.

      but I don't know of any off-hand.

      ccache is probably the least sucking one, but with a good build tree, makefile and strong TU seperation it's virtually never important anyway.

      --
      StoneCypher is Full of BS
  23. It can work by Foolhardy · · Score: 2, Interesting

    Including all the source code into one main file compiled to one object can work, if the source files cooperate. C can have problems with the namespace, but C++ allows multiple namespaces and you can even put the namespace blocks in the main file around the #includes. The source code has to support this, though. It's best if all the source files to be included are under your control. For libraries that expect to use a declarative header, use it like it was intended.

    I've done this on lots of projects and it works great. Most of the arguments here are either about performance or an appeal to tradition (that's the way we've always done it... must be the only true way). Modern compilers will create pre-compiled headers that can include code, usually used for template and inline definitions; modern compilers don't get the same benefits from the traditional model anymore. Actually, even larger projects seem to take longer to link with iostream and windows.h than the source does to compile.
    The compiler's ability to optomize code may be increased greatly, espescially its ability to inline functions. Too much inlining will cause code bloat, but the compiler's options should give you control over the balance.
    Modern compilers also allow you to change the compilation options mid-file.
    Any debugger or source analyzer shouldn't have problems handling inline or same-file implementations, or you're using bad tools.
    It can also be easier to create test code; create a series of test files t01.cpp, t02.cpp (each with a main) but include only one. The others are there for reference but don't interfere. This is also useful for testing a prototype replacement for a component; include the new one and comment out the old include. Going back is trivial.

    It's more a question of coding style than anything. Personally, I hate maintaining redundant information of any kind, and this very much includes the prototypes in the header with the actual functions. Source code redundancy is bad for all the same reasons that database redundancy is bad. Making my C++ member functions inline and including their files frees me from this.

    I don't think this will work too well in Java. A Java source filename = the .class filename = the ONE public class exported by the file. Unless you want a total of 1 public class, it won't work. Java doesn't use header files anyways. Class binaries export everything public automatically.

  24. Learn from others mistakes by GoofyBoy · · Score: 2, Interesting

    Its an interesting approach and you have no idea why you shouldn't do it.

    So do it.

    In the end, regardless if it works or not, you will have learned something new.

    --
    The surprise isn't how often we make bad choices; the surprise is how seldom they defeat us.
    1. Re:Learn from others mistakes by mvdw · · Score: 1
      Your Post:

      Its an interesting approach and you have no idea why you shouldn't do it.

      So do it.

      In the end, regardless if it works or not, you will have learned something new.

      Your sig:

      The surprise isn't how often we make bad choices; the surprise is how seldom they defeat us.

      Interesting juxtaposition...

  25. The immortal advice of Rocket J Squirrel by crmartin · · Score: 5, Insightful
    "Oh, Bullwinkle, that trick never works."

    One of the really depressing things about having been in the business for nigh on to 40 years now is that, along with the occasional new dumb idea, all the old dumb ideas keep coming back. Among those dumb ideas that keep coming back are "visual programming" --- using graphics instead of programming languages; complicated schematic graphics for software --- UML in its utter complex form; and, sure enough, using the preprocessor to mess with C-like languages.

    Every time this is tried --- and God knows it's been tried a lot --- you run into some severe problems:

    1. The scoping rules of C-like languages give semantics to file inclusion. If you #include chunks of code, you are defeating the language's (limited) ability to protect you from name space clashes, mis-named variables, and so on.
    2. While it might be that you gain something from only needing to start the compiler once, parsing and compilation are inherently a bit harder than O(n) where n is the number of source characters or tokens. A normal environment with make(1) will generally need to process fewer tokens than compiling everything all the time; the time required for a big file will inevitably dominate the startup time eventually.

      If you've got control of the compiler for this peculiar language, why not explore making the startup time shorter, say, eg., by using shared libraries, DLLs, or by setting the sticky bit?

    3. From sad experience, I can tell you that using the #include scheme will introduce weird-ass order dependencies into the code (ie., what order do you include files in?) that are very very difficult to debug.
    4. Most tools for C-based languages expect you to do the sources in a normal fashion. You confound the tools' expectations' at your peril.
    5. Similarly, most debuggers exploit, or attempt to exploit, scoping rules that you will break through this approach.
    6. When you write lots of smaller modules, each one can be create a single, small TEXT and DATA section, or a collection of small code sections. This makes the job of memory mapping in virtual memory systems much easier. Do it all as one big thing, and you're liable to get one big TEXT section.
    7. Optimization is comnbinatorially fairly hard, quadratic or worse, and global optimizations tend to be managed within section bounardies. One-big-module designs may either make the optimization phase very lengthy, or defeat optimization entirely when table space etc. runs out.
    8. You piss off every experienced C programmer who ever has to deal with the code in the future, especially old farts like me who've seen this trick 20 years ago.
    1. Re:The immortal advice of Rocket J Squirrel by Hard_Code · · Score: 2, Funny

      Yeah, seriously, you should be designing modules to interact through clean interfaces with known, published contracts. How you partition your compilation units should fall naturally from this. You shouldn't try to do the reverse and somehow "accrete" a design based on low-level preprocessor hacks.

      --

      It's 10 PM. Do you know if you're un-American?
    2. Re:The immortal advice of Rocket J Squirrel by Piquan · · Score: 1

      When you write lots of smaller modules, each one can be create a single, small TEXT and DATA section, or a collection of small code sections. This makes the job of memory mapping in virtual memory systems much easier. Do it all as one big thing, and you're liable to get one big TEXT section.

      That's the only one I don't buy. The individual text sections-- if they're even separate after ld is done with it-- will get merged into one big text section (along with the data and bss) when they're loaded into memory, and so the VM only has to deal with a range of pages, regardless of where the section boundaries were.

      The rest of your arguments were fine, and were why I cursed at my predecessors at my first real programming job.

    3. Re:The immortal advice of Rocket J Squirrel by Anonymous Coward · · Score: 0

      not if your job is to create shared libraries. Why suck in 15-20 functions when you only need one?

    4. Re:The immortal advice of Rocket J Squirrel by devillion · · Score: 1
      How would you then handle C++ templates (g++) ?

      template <typename T>
      void print_info(const T& t){

      std::cout << typeid(t).name() << std::endl;
      std::cout << t << std::endl;

      }

      Isn't that useful if you only instantate print_info() with handful of types.

    5. Re:The immortal advice of Rocket J Squirrel by stonecypher · · Score: 1

      Yeah, because clearly designing with a careful eye for scoping and without obvious abuse of inclusion mechanisms is exactly the same as design by contract, and in fact has anything to do with design accretion or preprocessor hacks.

      Also, the opposite. </jarvik>

      --
      StoneCypher is Full of BS
    6. Re:The immortal advice of Rocket J Squirrel by stonecypher · · Score: 1

      Awesome. You've just earned seat five on my friends list in seven years of slashdotting.

      --
      StoneCypher is Full of BS
    7. Re:The immortal advice of Rocket J Squirrel by crmartin · · Score: 2, Interesting

      Uh, which loader and which linker, and for that matter which operating system etc? I suspect you're right about linux, and it'd be lovely to believe that there aren't any systems (other than in hobbyists' basements) that don't do it that way any more, but with the information we've got, we can't exclude the possibility.

    8. Re:The immortal advice of Rocket J Squirrel by crmartin · · Score: 1

      Oh, God, RTTI and templates are such a pain in the ass. I'm not quite clear on what your argument is, but it is possible to do templates without doing textual replication and substitution, even in the presence of RTTI. This one's even pretty easy, with a hidden "class" object class method.

      But this would be one reason why RTTI is evil.

  26. comp.compilers thread on this subject by Anonymous Coward · · Score: 0

    Here's a post of mine to comp.compilers from 10 years ago....

    http://compilers.iecc.com/comparch/article/95-02 -0 74

    I believe that this strategy still makes sense in some environments.

    AG

  27. Re:Are you stupid? by BridgeBum · · Score: 1

    Isn't the article poster in favor of include files? He's looking for arguments to go to battle with the vendor. Is there something about using #include which seems stupid to you?

    --
    My UID is the product of 2 primes.
  28. Faster!?! Have you tried it? by multriha · · Score: 2, Interesting

    Well, coding style and software engineering aside, you need to do some testing if you think this will increase you speed.

    Quick test to illustrate. 1,000,000 lines of C code, using gcc 3.3.4, default options.

    Time to compile spread of 1000 files (with 8 lines of include and function body per file): ~2 minutes

    Time to compile all in a single file: unknown

    Why is the second time unknown? My computer doesn't have the memory to do it. Now I could pump up the memory of my machine (assuming I've got a 64-bit machine) to let me do the second compilation, but I doubt it'll be faster.

  29. Did you study computer science at ALL? by Pseudonym · · Score: 1

    If the amount of code changed or added in your program per unit time is roughly constant, then it will take O(N^2) time to compile, where N is the size of the program, over the life of the program.

    Think about that for a moment. Think back to computer science 101. Now ask yourself if this is a good idea or not.

    --
    sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
  30. You are solving the wrong problem by Chemisor · · Score: 3, Informative

    Speeding up a full build should not be important. The only people who care about it are in your test lab doing daily builds and regression tests, who can start the build overnight and have it ready by morning. Of course, this is the situation in a well-designed application. If you find yourself needing a full rebuild all the time, it means one of two things: 1. you are hacking a core component, or 2. all your components are written with spaghetti code and any change in one forces rebuilds in all the others.

    In the first case, try just testing one or two components during development, and then verify all the others when the API is stabilized. This is, incidentally, the advantage you gain from using header files: once the API is stable, you never need to rebuild that component again except to fix bugs (which require rebuilding only that component).

    In the second case, you need some serious refactoring. Look at the code and break it up. Encapsulate everything you possibly can. Make stuff private and static. Make everything you don't modify const. Keep it up until each component is accessed only through its API and that API is clean. Trust me, this is possible in any project. The enormous decrease in maintenance costs will more than pay for any time you spend on it.

    1. Re:You are solving the wrong problem by stonecypher · · Score: 1

      Speeding up a full build should not be important.

      Agreed.

      In the second case, you need some serious refactoring.

      Decoupling isn't refactoring. Fowlerian refactoring is about changing the interaction of code, the code paths, and pushing behavior around into conceptually correct normalized areas. Decoupling is just about specifying no more than the bare minimum information required for external linkage in order to reduce cross dependencies.

      Encapsulate everything you possibly can. Make stuff private

      Whereas these are good principles, it will have zero effect on the problem at hand.

      and static.

      No. Being static can introduce dozens of subtle bugs, particularly in threaded or reentrant code; unnessecary staticism is probably the single largest source of race conditions in C.

      Furthermore, this not only has no effect on compile time, but for primitive types doesn't have the speed increase effect most people seem to expect. Whereas it is true that this prevents a construction and destruction pass during an exit and entry, for primitive types that time is zero in any decent compiler anyway. By contrast, static UDTs are frequent sources of bugs which are generally too subtle for people which make this mistake.

      Static is a qualifier with important effects, like volatile, const, export and extern. To apply it in order to squeeze compilation speed is simply incorrect; a static variable is not the same thing as a normal variable in exactly the same way that a volatile or a const is not the same as a normal auto.

      Make everything you don't modify const.

      Yes and no. Const correctness is a deeper issue than this. Whereas things should be const by default, there are times at which constness is not conceptually correct despite that you won't be altering the variable in this particular use. In those cases do not apply const: not only does it enforce strong and contextually inappropriate strictures on users of the code, but can cause massive maintenance nightmares when you finally get around to using the mutable behavior of said code, and when during the repair of the const correctness mistake you discover that you have to overhaul 20% of your source base dependencies.

      --
      StoneCypher is Full of BS
    2. Re:You are solving the wrong problem by miu · · Score: 1
      Proper logical and physical encapsulation can speed up builds by a huge factor. The more extreme encapsulation of pimpl can speed builds even more.

      I think he is using 'static' in the sense of 'class variable' or maybe as in 'compilation unit scoped', not in the sense of 'persistent between invocations of a function' - the third use of 'static' is the one that always causes grief when threads enter the picture. You could conceivably cause thread problems with class variables, but to my mind that nearly always involves misuse of class variables.

      I agree that const correctness is somewhat complex, but many of the problems that require massive overhaul can be avoided by the mutable keyword.

      --

      [Set Cain on fire and steal his lute.]
    3. Re:You are solving the wrong problem by Chemisor · · Score: 1

      > Decoupling isn't refactoring.

      I would say that it is. Mathematically, if you convert (a+b/c)bc into abc+bb and then to b(ac+b), I call it refactoring, since it involves moving factors around. In programming I say "refactoring" to mean "extract interfaces from your code and use them to pull up modules, which can then be encapsulated into classes".

      >> Encapsulate everything you possibly can. Make stuff private

      > Whereas these are good principles, it will have zero effect on the problem at hand.

      It will have a great deal of effect on the problem at hand, which is the increasing the speed of developer builds. If your modules don't let their intrails hang out, changing them does not require rebuilds anywhere outside the module. This is the only real way to solve the problem.

      > No. Being static can introduce dozens of subtle
      > bugs, particularly in threaded or reentrant code

      Well, yes; I should have made it more clear that I meant static functions in C, which simply mean that the named function is not used outside the file. The other important use of static is for const arrays inside functions, which should be declared static to allow the compiler to put them in the data segment at compile time instead of building them whenever the function is entered.

      As for threaded code, I never write any; in my experience, event-driven asynchronous designs give much better and faster results, because the lack of any data sharing bugs, race conditions, and locks makes debugging easier, and the absence of context switches makes the CPU happier. It also makes data-coupling of components easier.

      > Furthermore, this not only has no effect on compile time,
      > but for primitive types static doesn't have the speed
      > increase effect most people seem to expect.

      Actually, it may decrease performance by causing a cache miss. Local variables on the stack would already be in cache because the top of the stack is a heavily used area, while the data segment, where static variables are, is accessed rarely.

      > Whereas things should be const by default, there
      > are times at which constness is not conceptually
      > correct despite that you won't be altering the
      > variable in this particular use.

      This is more about interface design, where it is indeed important to determine what is mutable and how. Obviously, in such a case the "make everything you don't modify in const", would not apply. You'd actually have to think :)

      > when during the repair of the const correctness mistake
      > you discover that you have to overhaul 20% of your source base dependencies.

      But implementing const correctness in the first place has a much higher cost. I had a job once where I overhauled about 100000 lines of code in trying to implement const correctness. That was about 70% of the codebase. It was all written by people who never used const.

    4. Re:You are solving the wrong problem by stonecypher · · Score: 1

      Proper logical and physical encapsulation can speed up builds by a huge factor.

      True. That doesn't make statics encapsulation at all, let alone proper.

      The more extreme encapsulation of pimpl can speed builds even more.

      It's always a shame when people talk about sutter's pointer to implementation or fast pointer to implementation idioms without actually understanding them. Pimpl is not encapsulation. Encapsulation is the seperation of implementation from interface, the distinction between "inside" and "outside." Pimpl does not change what is inside or outside; it simply moves the implementation's guts deeper down in order to make operations like copying and pooling faster.

      I think he is using 'static' in the sense of 'class variable' or maybe as in 'compilation unit scoped', not in the sense of 'persistent between invocations of a function'

      I should hope not: class statics and local/global statics are not distinct in any way, and in context file statics don't make sense.

      the third use of 'static' (local statics) is the one that always causes grief when threads enter the picture.

      Uh. Consider a singleton flyweight head which has two threads attempting to add to the same weight at the same time. Even though it's a "class variable," there's a race condition.

      You could conceivably cause thread problems with class variables, but to my mind that nearly always involves misuse of class variables.

      Explain to me please a legitimate use of a class static which does not threaten race conditions absent locking or mutexing. Five points if your explanation does not hinge on a program which is single threaded by nature, making the example utterly useless.

      but many of the problems that require massive overhaul can be avoided by the mutable keyword.

      No, they can't. Digging yourself deeper into incorrect const behavior is not a solution to earlier const correctness behavior. You would do well to dig around the c2 wiki, where these issues are discussed at great length.

      --
      StoneCypher is Full of BS
    5. Re:You are solving the wrong problem by stonecypher · · Score: 1

      Decoupling isn't refactoring.

      I would say that it is. Mathematically, if you convert (a+b/c)bc into abc+bb and then to b(ac+b), I call it refactoring, since it involves moving factors around.


      Neat how you avoided the justification I gave, and instead relied on equivocation to make your argument for you. It doesn't really matter that in mathematics you can push things called factors around; that has nothing to do with Fowlerian refactoring. Should you choose to read his book, you may be surprised to learn that he himself places great emphasis on the distinction between modularization and refactoring.

      n programming I say "refactoring" to mean "extract interfaces from your code and use them to pull up modules, which can then be encapsulated into classes".

      1) That is an extremely specific case of modularization which happens to also be a case of refactoring; this is a fallacy of composition, wherein you are suggesting that because one extremely limited case is in both sets, then the two sets are equivalent.

      2) It doesn't matter how you use the word; that's just not what the word means. I might say "I use the word rape to mean planting flowers on highways;" that doesn't mean that I may then engage in discourse about landscaping with the word rape.

      3) Refactoring is a hell of a lot more complex than hand-encapsulation.

      It will have a great deal of effect on the problem at hand, which is the increasing the speed of developer builds. If your modules don't let their intrails hang out, changing them does not require rebuilds anywhere outside the module. This is the only real way to solve the problem.

      In the case of code with extreme coupling problems, this will actually make things worse. The problem is that coupling is the result of code swatch A requiring knowledge about code swatch B. Encapsulation does not decrease coupling in any way; it simply hides non-coupled parts from one another. Whereas that is certainly a Good Thing (tm), it will not address issues of coupling. Rather, it will force the programmer to bring more interface knowledge to various points within the program, increasing coupling, and thereby deepening the problem wherein code A requires a rebuild of code B to run, even though code B is unchanged. This is why I suggested Alexandrescu-style functors: they have an immediate decoupling effect.

      No, this will not have any effect on the problem at hand.

      Well, yes; I should have made it more clear that I meant static functions in C, which simply mean that the named function is not used outside the file.

      Oh yes, I should have made it clear that I meant a crib mobile which moved itself, not a car, when I said automobile. You should realize that statics are static variables, and that static functions, despite having static in their name, are not statics at all.

      The other important use of static is for const arrays inside functions, which should be declared static to allow the compiler to put them in the data segment at compile time instead of building them whenever the function is entered.

      Static doesn't have any such effect on UDTs, and on machine types that already happens. This is myth: static local arrays are not in any way faster than nonstatic local arrays. Please try profiling such code in a relatively modern compiler; you should see absolutely no difference at all, like I see with gcc 3.1+, bcc 5.5+ and mscc 7.1 .

      As for threaded code, I never write any

      Obviously. You also clearly don't write libraries, where you cannot guess about the nature of outside code. Furthermore, you plainly don't write code which is maintained by others.

      event-driven asynchronous designs give much better and faster results

      Uh. You do realize that the event mechanism i

      --
      StoneCypher is Full of BS
    6. Re:You are solving the wrong problem by miu · · Score: 1
      pimpl is very much a separation of implementation from interface - information hiding is essential to encapsulation.

      You mention the most common legitimate use of class variables, the singleton. Obviously that requires some form of mutex. The common use of 'const' class variable is naturally thread-safe, so are class methods.

      mutable does nothing to dig you deeper into a const trap, it should be used when laying out the class to mark those portions that don't affect the logical constness of instances of the class. This makes it easier to keep to keep to correct application of const in the first place.

      --

      [Set Cain on fire and steal his lute.]
    7. Re:You are solving the wrong problem by stonecypher · · Score: 1

      pimpl is very much a separation of implementation from interface - information hiding is essential to encapsulation.

      pimpl has nothing to do with information hiding. This is a non-sequitor. Pimpl is in effect a c-focussed version of the Handle pattern. It is used to prevent long copy times on large objects and to prevent vtbl change from breaking dependant code. Before you get in a fit about how isolation from vtbl change is somehow an encapsulation issue, please take the time to consider that adding a single private member enacts this fault; this is not about information hiding, no matter how badly you may want for it to be.

      You mention the most common legitimate use of class variables, the singleton. Obviously that requires some form of mutex.

      Amusingly, no, it doesn't - the typical singleton is almost the only place wherein a member static is safe against race conditions without a mutex, assuming that you have a safe cleanup pattern and can make class creation atomic.

      mutable does nothing to dig you deeper into a const trap,

      It does when you use it to undo an existing overconst block of code, as you suggested.

      --
      StoneCypher is Full of BS
    8. Re:You are solving the wrong problem by miu · · Score: 1
      And what is the handle pattern but an application of information hiding? An opaque type hides information from disinterested parties. To my way of thinking that, rather than simple aggregation, is the essence of encapsulation. pimpl gives the benefit of vtbl isolation, but that arises as an additional benefit - not the sole purpose.

      You need a mutex for singleton to avoid a possible race condition at creation. Atomic class creation can only be achieved by creating the instance yourself, you can not be guaranteed client programmers will do so correctly (library init functions which can enforce this often seem to cause more trouble than they are worth), and it is not something you can count on the environment to do in a portable way.

      The addition of mutable I suggested is a remedy when the initial class layout did not use it appropriately.

      --

      [Set Cain on fire and steal his lute.]
    9. Re:You are solving the wrong problem by stonecypher · · Score: 1

      And what is the handle pattern but an application of information hiding?

      I have explained this twice already. Decoupling is not encapsulation, even though the two go together quite frequently. Pimpl applies to pure-private classes, POD, and in situations where encapsulation simply does not factor into play. Before you ask me that a fourth time, please read my first three answers. Repeating myself is getting quite annoying.

      pimpl gives the benefit of vtbl isolation, but that arises as an additional benefit - not the sole purpose.

      If you would take the time to read the book from which pimpl comes, you would realize that the two reasons I lsited are in fact the reasons it was created.

      You need a mutex for singleton to avoid a possible race condition at creation.

      Not for things with atomic creation. I'm sure you'll point out that you discussed atomic creation, except that what I said was predicated on creation being atomic; therefore this is a non-argument.

      Atomic class creation can only be achieved by creating the instance yourself

      This is simply false. There are many techniques for achieving atomization. Take a look into non-mutexed threadsafe containers; they're not running on magic, and they work just fine with any UDT you want to throw at them.

      you can not be guaranteed client programmers will do so correctly

      Non-sequitor. Client programmers have nothing to do with the constructor of an object in a library they did not write.

      (library init functions which can enforce this often seem to cause more trouble than they are worth)

      What do library init functions have to do with atomic construction of an object? Hint: nothing.

      --
      StoneCypher is Full of BS
    10. Re:You are solving the wrong problem by stonecypher · · Score: 1

      In fact, since you've shown a remarkable tendency to ignore things named for the specific purpose of looking things up, let me just save us both some trouble.

      class AtomicSingleton {

      public:
      AtomicSingleton* Instance();

      protected:
      AtomicSingleton();

      private:
      AtomicSingleton* instance;

      };

      AtomicSingleton::Instance() {
      if (!instance) {
      AtomicSingleton* workspace = new AtomicSingleton;
      if (!instance) {
      instance = workspace;
      } else {
      delete workspace;
      }
      }
      return instance;
      }


      Gee, that was hard. *cough*

      --
      StoneCypher is Full of BS
    11. Re:You are solving the wrong problem by miu · · Score: 1
      Gee, that was hard. *cough*

      There is a race condition you ignore that can only be avoided by assuming that AtomicSingleton::Instance is called at least once before any additional threads are created. That is the "non-sequitur" I made about library initialization.

      The argument about the meaning of encapsulation has become completely meaningless, we disagree about the meaning and spirt of it and I'll leave it at that.

      --

      [Set Cain on fire and steal his lute.]
    12. Re:You are solving the wrong problem by miu · · Score: 1
      If you would take the time to read the book from which pimpl comes, you would realize that the two reasons I lsited are in fact the reasons it was created.

      pimpl is one of those things which is perpetually rediscovered by every student of C++ (with a few minor variations), even the name is a convention that is often used by independent discoverers. As far as books go Sutter covered it, Meyers covered it, Lakios covered it, and I'm sure half a dozen faqs have covered it. Different books recommend the technique for different reasons.

      --

      [Set Cain on fire and steal his lute.]
    13. Re:You are solving the wrong problem by stonecypher · · Score: 1

      There is a race condition you ignore that can only be avoided by assuming that AtomicSingleton::Instance is called at least once before any additional threads are created.

      What the hell are you talking about? It doesn't matter if threads are created before a singleton. Could you be any more random?

      That is the "non-sequitur" I made about library initialization.

      Again, I know this is difficult for you, but try to keep up: library initializatin has nothing to do with class constructors.

      we disagree about the meaning and spirt of it and I'll leave it at that.

      Maybe you should read TC++PL or the standard, where it's clearly defined. I really don't care what you want to believe: the word has a concrete meaning, and whereas you can ramble on using it to mean any random thing that pops into your mind, you're still wrong. There's nothing more to it than that: if you use a term in regards to C++ in a way contrarian to the standard, you are wrong.

      Make all the childish "I meant something else and you don't agree so it's a nonissue" arguemnts you want; you're not correct, and you're not going to become correct by making ridiculous seperations from the real meaning of terms. This is one of the primary signs of a rank amateur.

      --
      StoneCypher is Full of BS
    14. Re:You are solving the wrong problem by miu · · Score: 1
      What the hell are you talking about? It doesn't matter if threads are created before a singleton. Could you be any more random?

      The race condition is in the following code.

      if (!instance) {
      AtomicSingleton* workspace = new AtomicSingleton;

      Now imagine the following:

      in thread 1:
      if (!instance) # true
      # thread stops running
      in thread 2:
      if (!instance) # true

      See the problem, both threads can now continue on to the new. If Instance has not been called at least once before multiple threads are running then two singleton objects can be created.

      >> The argument about the meaning of encapsulation has become completely meaningless, we disagree about the meaning and spirt of it and I'll leave it at that.

      > Maybe you should read TC++PL or the standard, where it's clearly defined. I really don't care what you want to believe: the word has a concrete meaning, and whereas you can ramble on using it to mean any random thing that pops into your mind, you're still wrong. There's nothing more to it than that: if you use a term in regards to C++ in a way contrarian to the standard, you are wrong.

      The C++ standard has absolutely nothing to say about the meaning of encapsulation and very little to say about OOP. Stroustrup has very little to say about encapsulation, aside from defending the 'friend' mechanism in D&E. I did find a few words about exactly what encapsulation means in non-standards sources. Plauger: "encapsulation: localizing a design decision so that a change of design results in changes within a small and easily identified region of source text" - C++STL. Stutter: "Here encapsulation is used in the sense of bringing together in one place, rather than hiding behind a shell." - MEC++. Stan Lipman clearly identifies encapsulation with information hiding in every instance in his Primer.

      I was being polite in my disagreement with you, but you have been exceptionally rude. My statement that "we disagree about the meaning and I will leave it at that" was an attempt to slow down your hostility, because honestly the argument doesn't mean that much to me.

      --

      [Set Cain on fire and steal his lute.]
    15. Re:You are solving the wrong problem by stonecypher · · Score: 1

      See the problem, both threads can now continue on to the new. If Instance has not been called at least once before multiple threads are running then two singleton objects can be created.

      Read the code again. This is accounted for.

      My statement that "we disagree about the meaning and I will leave it at that" was an attempt to slow down your hostility

      The hostility wasn't there until you spent three generations of message ignoring the same question over and over again, like you've done yete again here.

      --
      StoneCypher is Full of BS
    16. Re:You are solving the wrong problem by miu · · Score: 1
      The second check of the value of instance for the purpose of assignment of workspace to instance misses the fact that new itself can be called multiple times. One of the points of singleton is that multiple instances of the class are undesirable or possibly dangerous. A second check of the value of instance without a mutex only ensures that the correct pointer is returned.

      AtomicSingleton::Instance() {
      if (!instance) {
      mutex_lock();
      if (!instance) {
      instance = new AtomicSingleton;
      }
      mutex_unlock();
      }
      return instance;
      }
      --

      [Set Cain on fire and steal his lute.]
  31. Re:Interface vs implementation, shared libraries, by aled · · Score: 1

    Header files aren't a good way to separate interface from definition. For one, the programmer can still put the entire program code in the header file. And in C++ the private parts of classes end in there too.
    Java and Delphi use just one file but the interface could be easily obtained from the binary object. That way prevents duplicate definition and I like it better.

    --

    "I think this line is mostly filler"
  32. Mutually recursive functions? by Anonymous Coward · · Score: 0

    It seems there are two separate issues, with different pluses and minuses.

    The first is eschewing .h files and the whole separate declaration/definition thing. The second is compiling it all together in one compiler invocation.

    Regarding the first, a master "project.c" file #including all the other .c files is, IMHO, a bad idea.

    Having a declaration in scope (i.e. included in the source prior to) at the time of the function call is a good thing. Otherwise ANSI C defaults to K&R rules, and you're not allowed to call variadic functions at all.

    If you don't have separate declarations preceding definitions, how do you resolve the ordering problem for mutually recursive functions? For example, suppose foo() calls bar(). And bar() calls foo(). What order do you define them in?

    Even without this, you could have icky ordering requirement between source files, where foo.c:foo2() calls bar.c:bar() calls foo.c:foo1(). Do I include foo.c or bar.c first in the master source file?

    Far better, IMHO, would be to mark exported functions, structures, etc. in the source somehow, and write a tool that automatically pulls the info out of the .c files into a .h file. You could make a single "project.h" file which everything includes. The only downside is that you have to recompile all source if any header file changes.

    As for a single compiler invocation being faster, the only thing you lose is file-scope static variables and helper functions. Personally, I find this useful (and wish C had features to share a scope among a few related files), but I also try to keep such names globally unique for debugging purposes anyway. If you can live with that, a single compile is far less of a silly thing to do. But you can just #include all the header files, then all of the .c files, or something like that. It doesn't necessarily go with eliminating .h files entirely. Personally, I find incremental recompilation a useful speedup, but whatever works for you.

  33. Re:Interface vs implementation, shared libraries, by WaterBreath · · Score: 1
    you can't separate template declarations from their definitions

    You can separate them, somewhat. You can separate them into separate headers. Put the declaration in one, then the implementation in another, and put a #include for the implementation in the declaration file, after the actual declaration.

    I know this isn't technically the same. The implementation is still in a header, but there's really nothing to be done about that because of the way C++ implements templates under the sheets. But for the purposes of code clarity, it's nearly identical.

  34. Wow. by Karma+Farmer · · Score: 1

    First, your language is not like anything like Java, because Java does not have header files at all.

    Second, your language is not anything like C, because C was carefully designed from the ground up to use header files and compilation units. Running this way will annoy your compiler, your linker, your debugger, and every other link on your tool chain, and muck up many standard C coding practices.

    So, yeah. If you're using a language that's not like C or Java, and your tool vendor is telling you to do this, and your lead developer is telling you to do this, and your managers trust the lead developer's decisions, then do it. Your project isn't going to succeed or fail based on this decision.

    1. Re:Wow. by stonecypher · · Score: 1

      Running this way will annoy your compiler, your linker, your debugger, and every other link on your tool chain, and muck up many standard C coding practices.

      Conspicuously absent from this list is "other programmers."

      --
      StoneCypher is Full of BS
    2. Re:Wow. by Anonymous Coward · · Score: 0

      Java has header files, they're just called interfaces.

  35. Use smaller fonts by mgkimsal2 · · Score: 1

    In your IDE, change the code to be a smaller font - this will use less disk space and ultimately make things run faster...

    1. Re:Use smaller fonts by crmartin · · Score: 1

      OKay, this one made me laugh. Virtual Mod FUNNY.

  36. Re:Interface vs implementation, shared libraries, by miu · · Score: 1
    The .i/.impl/.template convention for including the template implementation from the header is fairly widespread and works as well as anything related to templates ever works.

    The "pure" solution of actual separate compilation of template implementation is supported by some compilers, but the complication it adds to the linker is probably more trouble than it is worth.

    --

    [Set Cain on fire and steal his lute.]
  37. Oy vey. by stonecypher · · Score: 1

    You don't want to abandon headers; they are the basis of seperation into translation units. If you're compiling from the top and it's faster than compiling small pieces, then that means your source needs a hell of a lot more decoupling; by definition the only way that top-down build could possibly be faster than incremental build is if incremental build is still making everything anyway.

    Consider reading Modern C++ Design, specifically the section about generic functors, which should help you with your coupling problem until you have the time to learn to seperate TUs aggressively on your own. In my opinion, the Boost functors are better than the Loki functors, but the book is a hell of a lot better than the Boost documentation, so read it anyway.

    Ask a large project supervisor in a company with aggressive compilation tactics about the large compile-time wins of precompiled headers. Whereas it's not the same issue, the same critical foundations are there, and it's generally easier to squeeze out an answer about PCH than properly seperated TUs.

    --
    StoneCypher is Full of BS
  38. Re:Interface vs implementation, shared libraries, by EsbenMoseHansen · · Score: 1

    Nothing prevents you from doing so in C++ --- try man nm.

    However, the interface you get this way is not very well documented --- in Java or C++. For this reason, most people doing C++ (and Java) uses comments in the source files, which are then transformed into documentation by doxygen and similar programs (like javadoc).

    --
    Religion is regarded by the common people as true, by the wise as false, and by rulers as useful.
  39. RFC1925 by Anonymous Coward · · Score: 0

    One of the really depressing things about having been in the business for nigh on to 40 years now is that, along with the occasional new dumb idea, all the old dumb ideas keep coming back.

    This is just a matter of being standards compliant, see #11 in http://www.faqs.org/rfcs/rfc1925.html.

  40. Re:Interface vs implementation, shared libraries, by aled · · Score: 1

    It isn't exactly the same. nm works just with some compilers (or is it a gcc only utility?), and can't really extract all the type information, that isn't really there. Except may be in C++ decorated object code but I don't remember it now.
    Also most C/C++ code doesn't make clear in a nm listing which aftifacts are public, a programmer has to extra steps to prevent this. nm is at least confusing when you want to get the public API of an object compared to other language tools that just do it.
    I'm not an expert in nm, feel free to correct me if I'm wrong.

    --

    "I think this line is mostly filler"
  41. Total red herring... by pla · · Score: 3, Informative

    First of all, "speed", either compilation-wise or runtime-wise, has nothing to do with why you should use header files.

    I too disliked header files, long ago, in my early days of programming C. It seemed pointless, to have two files (or rarely, as many as four), when one would do just as well.

    For small projects, I'll still use one large monolithic source file. In that aspect, it makes sense to skip breaking out your data and function definitions.

    But when you get to the "real" world... Imagine even a "small" serious project, with perhaps 10k lines of code. Try to find a single function in that file - I hope you feel on good terms with your IDE's search capabilities!

    So, break that out into a dozen files - You have your network code in one file, your UI code in another, your file I/O in another, perhaps some database interaction in another, and so on. Okay, that works well... But wait, your network code, your file I/O, and your database code, all make use of the same checksum algorithm! So, you have the same exact code duplicated three times.

    That would work, because each file will compile to a module with its own namespace (in most languages). But it wastes space, both in the source and in the compiled code. It also wastes time and can very easily introduce bugs - For example, if you decide you need to switch from MD5 for SHA1 as your checksumming algorithm, you now need to change three places instead of one. If you miss one of those, but use them to compare results between the three different uses, you have a very serious bug that may drive you batty trying to track it down.

    So, the obvious solution, break out all your common functions into a toolkit-like source file. Now, you could just #include that in every other file that needs it, but WOW would that cause some serious bloat in the compiled code - In my experience, shared code files frequently end up as the single largest source file in the entire project.

    So, use a header file. That way, you don't end up with massive duplication of code, you have the advantage of a logical breakout of your code into similar-purpose files, and you can still make changes to only one file to modify one function.

    Incidentally, the above chain of thinking more-or-less describes the evolution of standard libraries... Would your professor actually suggest that you shouldn't "#include<stdio.h>", but instead should manually pull the code for each function you use into your source file? Because, in the degenerative case, he has told you exactly that.

  42. Re:Interface vs implementation, shared libraries, by EsbenMoseHansen · · Score: 1

    Well, nm is from binutils. It's certainly not gcc only --- it can read various object file formats. Anyway, surely you are only interested in those that your linker, ld, can actually read.

    It is true that nm is faithful to the object code, in that "private" artifacts and type info in C (C++ has them, as you suspect, encoded into the name, much like Java) are listed. This reflect the fact that nothing prevents you from modifying a header file to use a private artifact --- it's a compiler thing, not a linker. I'm not famliar enough with Java to know if accessibility is enforced down at the runtime level. It seems a counter-constructive thing to do, but maybe there is something about Java that forces this to be so.

    However, my point was that even with private/public adoration, the API you get is rather useless. It's very well to know that a constructor for a rectangle takes for doubles as input, but would that be lower left corner, height and width? Does the class require that the height and width (parameters) to be positive? How about 0, is that ok? If I copy a rectangle, would that be a deep or shallow copy? Is the constructor thread-safe?

    All this is usually documented in comments in the code --- doxygen or javadoc. And there you get the full API for free anyway, with clickable links and everything. What's the point in jerking around with object/bytecode when you have this?

    --
    Religion is regarded by the common people as true, by the wise as false, and by rulers as useful.
  43. Re:Interface vs implementation, shared libraries, by miu · · Score: 1
    The programmer can easily subvert the type, scope, and privacy level of any source or binary interface you can come up with, the requirements of C compatibility require that it work this way.

    One of the better ways to discourage client programmers from subverting your interface is to use as the only private member a pointer to an implementation struct which is forward declared in the header and defined within the implementation file. This can seriously cut down dependancies in large projects and remove one of the "practical" reasons programmers may have for subverting your interface.

    --

    [Set Cain on fire and steal his lute.]
  44. Re:Interface vs implementation, shared libraries, by aled · · Score: 1

    I agree with you, my point is that having separate definition/declaration files is useless and redundant. You can have the docs generated or -at least in java- can have the exact prototypes generated from the binaries. There's no technical need to includes nor is needed for documentation. That's why I like it better the Java/Delphi way than C/C++ #includes.

    --

    "I think this line is mostly filler"
  45. Wrong. by Anonymous Coward · · Score: 0

    If your language supports "static" in the file-scope sense, you could declare every global object as static and reap the compiler optimizations that come with that declaration.

    Er. There are no optimizations which apply to globals but not to globals. No, that's not a typo: file-scoped variables are globals whose names are not imported into the external tokenspace. There is no difference from the perspective of the compiler between the two; file-scoping is a purely lexing issue, and lexing cannot optimize in any way.

    Wrong. If the compiler sees that a "global" (ie. the outermost scope) variable, a is declared static, then it knows that the value of that variable cannot be changed by other code outside the current translation unit. That might enable some optimizations which would not have been possible before (in particular, it may be possible to put the value into a register and keep it there for longer).
    1. Re:Wrong. by stonecypher · · Score: 1

      Wrong. If the compiler sees that a "global" (ie. the outermost scope) variable, a is declared static, then it knows that the value of that variable cannot be changed by other code outside the current translation unit.

      A variable which isn't extern already has this facet. There is no change once you introduce file scoping. Don't be silly.

      That might enable some optimizations which would not have been possible before (in particular, it may be possible to put the value into a register and keep it there for longer).

      Uh. You really think that a variable might be left on the register for a different amount of time based on instructions to the linker? Have you yet realized that if you file-scope a variable and recompile you get the exact same assembly, and that like namespaces, file-scoping has literally no effect on the binary, that it's entirely a language-level safety for the programmer?

      --
      StoneCypher is Full of BS
    2. Re:Wrong. by Anonymous Coward · · Score: 0
      I don't suppose you've actually tried it on a real compiler. The only thing you need the 'extern' for is to expose the definition in a different file (which is why the extern declaration usually goes into a header file); simply declaring a non-static global variable will allow external linkage. The variable must be declared without extern at least once somewhere, or else it's not going to be linked to an actual memory location, and the linker will throw up an unresolved symbol error.

      myfile.h:
      extern int a_global_variable;
      myfile.c:
      #include <myfile.h>

      int a_global_variable;
      yourfile.c:
      #include <myfile.h>

      static void
      set_a_global_variable(void)
      {
      a_global_variable = 1;
      }
      Functions are weird in that they don't require extern, or even prototypes, although it's good practice and all.

      Try running objdump on some .o files, and compare the difference between static and non-static variables some time. Static makes external linkage impossible; non-static simply makes it harder to do (requires an extern to avoid compilation errors). File scoping is thus quite important in good C engineering, where we don't have access to fancy C++ extensions like private.

      Since static restricts possibly aliasing at the program level, the compiler is free to make additional optimizations by considering just a subset of the program at the file level, rather than being forced to make (possibly computationally infeasible) global optimizations at the program level.

      Maybe you ought to consider your facts first before going off and attacking hapless C programmers who probably know their business better than you seem to.
  46. Re:Are you stupid? by Profane+MuthaFucka · · Score: 1

    The author is considering NOT using include files, rather than laughing at the vendor and reminding him where his money supply originates.

    --
    Fascism trolls keeping me up every night. When I starts a preachin', he HITS ME WITH HIS REICH!
  47. Re:Interface vs implementation, shared libraries, by EsbenMoseHansen · · Score: 1

    This is my favorite gripe with C++, so I agree with you that is seems silly and redundant.

    However, you could get close to the Java way by just writing the class out like in Java in a C++ header file. We have to ask ourselves the question: Won't don't C++ programmers do this? Force of habit? Compile times? Group pressure? Or is it, after all, better this way?

    Another thought: Nothing would prevents header file being automatically generated from source files, though a few extra comments would be neccessary like /*+ public: */ and /*+ virtual*/ Why has this not been done? Don't tell me nobody thought of it :)

    --
    Religion is regarded by the common people as true, by the wise as false, and by rulers as useful.
  48. removal of duplication is usually a good thing by mqx · · Score: 2, Interesting


    Just remember that a header file defines the interface to the body: which actually duplicates some of the material in the body. Because of this duplication, you can have problems, i.e. faulty build dependencies, mismatch between header/body, etc. Removing this sort of duplication is usually a good thing: so if the technology (i.e. compiler) is smart/performance/etc to get it right, then the change could be a good thing.

    I'd like to point out that many other respondants have argued their case with reference to 'C', however the poster clearly said it was not 'C' -- without further information, it's difficult to know whether these 'C' type issues will translate. I'd point out that some languages, e.g. python, java, perl, do not have ideas of separate header/body -- suggesting that "current trends" in languages is to do away with the duplication.

    The compiler could be intelligent enough to construct a parse tree quickly, and only resolve parts of the parse tree when necessary: so for example, if there was previously a 5K header, and a 30K body, but now only a 30K body, the compiler may read the entire 30K, and only "roughly" parse it (e.g., say for a function, it parses the outer scope of the function, but resolves nothing inside the function until some other code actually uses the function).

    I don't think there's an answer for this guy: there are too many issues that haven't been stated, as we know nothing about the particular toolchain, the build environment, the language, etc. All we have an abstract concept of splitting files into header/body. That concept by itself isn't good or bad, it depends upon a lot of other issues that change the perspective.

    My answer would be that surely in the guys company he has a couple of clueful senior engineers that can sit around a whiteboard and discuss (using their computer science training) what actual impact the change will have on the project, and whether to go with the impact.

  49. More from the author by garethw · · Score: 2, Informative
    Thanks for all the interesting replies. It's always nice to start a flame war.

    I wish I'd included a few more details, which might have avoided questions like, "Are you stupid?" and "Have you taken basic Computer Science course?" (the answers are "On occasion" and "Waterloo, Comp Eng '98" respectively :) )

    A few details which might put the question into perspective might be:
    • The project is a chip verification project. There is no final "product" at the end of my work. The name of the game is endlessly re-compiling and running new tests. So compile time is actually quite significant.
    • There is no linker. :) The nature of the language is such that it is linked at run time.
    • The compiler actually doesn't allow you to list multiple source files on the command line and produce one object. So I guess my C/Java analogy was misleading. But that's partly why I'm at a loss to rationalize the question - there is little direct reference point.
    • A lot of people missed my point - I think abandoning header files is abhorrent. But when it came down to it, I couldn't actually produce any inarguable reasons why (namespace is one, but I don't think it's a show-stopper).
    Thanks again for your insights.
    --
    garethw
    1. Re:More from the author by gatkinso · · Score: 1

      I haven't read the flames yet, but.... asking for specific advice when you won't a) reveal what language the code is in, or b) what compiler is being used sort of invites flames.

      Candidly, how do you expect a serious (not to mention informative) response?

      OK - now to read the flames....

      --
      I am very small, utmostly microscopic.
    2. Re:More from the author by garethw · · Score: 1

      I think I got a number of serious responses and a few informative ones, too.

      I'm guessing that very few people on /. know what Vera is, and I didn't want to limit the responses who are ASIC verification engineers.

      I think it was quite a useful exercise, actually.

      --
      garethw
    3. Re:More from the author by JWhitlock · · Score: 1
      I wish you would have included these details - you would have gotten a better response, from people experienced in your environment.

      The important thing is that your language might look like C or Java, but it sounds like it is very different in practice. So, on this one, you can't really lean on your C and Java experience to help. You have to either trust the vendor, or run some experiments yourself.

      In the case of C, it is an interesting excercise to just run the preprocessor, and see the result. In gcc, the option is "-E". This will expand macros, add in header files, etc. etc. In this way, there is no difference between cutting and pasting and #including a file. Your compiler doesn't really care.

      Of course, it matters a great deal to people. We need clear interfaces, well documented and self-documented code, hiding of details behind a useful abstraction, debugging tools, and all the things that make us humans rather than compilers. In our world, programs cleanly divided into headers makes more sense.

      I imagine in your case, the "compiler" is different than traditional C/C++ compilers. If you have a header file Code.h that declares "extern int my_global_var", and a source file Code.c that defines "int my_global_var", it is perfectly obvious to you where the definition of my_global_var is. To you compiler, it is not clear - there is no reason why Code.h and Code.c have to be related at all. So, it may have to search ALL the source files in a directory, to find where that global variable, or a function, class, etc., is actually defined.

      To prevent this search, the vendor is suggesting that you #include all the source, and thus use the preprocessor to gather up all the code at once. Now, all the declarations and definitions are in a single unit, and the "compiler" doesn't have to search files - maybe.

      This would be horrible and wrong if it was a C compiler. But it sounds like it isn't - it just uses a syntax that looks like C (again, I wish you'd just say what the product is, so we'd stop guessing). So, forget that it looks like C and sometimes acts like C, and start experimenting.

  50. For release, but not development by bluGill · · Score: 1

    There is what you do for release, and what you do for development. For release (which can include the daily build!) this is a good idea, if there is any gain in run speed.

    For development I consider this a bad idea. When I change foo.c I don't want to recompile every other file in the project. It will slow things down in any project with size.

    It will be more work to implement both. Since computer time is cheaper than human time most people don't bother with adding the ability to do both. However I wouldn't call it a bad idea for releases.

  51. Parent has obviously never woirked w Modula-2 by maysonl · · Score: 1

    ...or has forgotten everything he ever knew about it.

  52. This isn't C++ or Java by Anonymous Coward · · Score: 0

    The answer has to be "we don't know" because you haven't told us what language this is. I reckon it's some sort of verilogrevolting or system-Cyukyuk abomination, in which case I would say *** do what the vendor tells you *** because if you don't and it all falls apart they will say "we told you so".

    But just imagining that it was C after all, here's an annecdote. I wrote an instruction set simulator once. It looked like this:

    switch(opcode) {
    case 0: foo(...); break;
    case 1: blah(....); break;
    case 2: blob(....); break; ......
    }

    There were many many lines in the case statement; the functions were defined in other files and were mostly short, e.g.

    void add(int a, int b, int& c) { c=a+b; }

    In this case, replacing '#include "add.h"' with '#include "add.c"' for each of the files gave a huge increase in execution speed since the functions all got inlined, but of course compilation time is reduced in the typical case where only a few files have changed. Solution:

    #if compile_fast
    #include "add.h" ...
    #else
    #include "add.c" ...
    #endif

    Plus some magic in the Makefile. Useful when you have a problem like this, but *most problems aren't like this*.

    You can also make comparisons with the way that the C++ STL is defined purely in headers. Slow to compile, larger code size, but fast.

    1. Re:This isn't C++ or Java by garethw · · Score: 2, Interesting

      The answer has to be "we don't know" because you haven't told us what language this is. I reckon it's some sort of verilogrevolting or system-Cyukyuk abomination,

      Not a bad guess. It's Vera. But what's the point of telling people that? How many people on slashdot even know what Vera is?

      in which case I would say *** do what the vendor tells you *** because if you don't and it all falls apart they will say "we told you so"

      But what's messed up is that vendor just decided to start advocating this one day. The Vera compiler even supports header generation - it's been done the way we expect for years. And bang, one day they suddenly start encouraging this weird approach. "What the vendor tells me" is not what the vendor told me five years ago, or last year.

      I know that there was some discussion sparked internally at the vendor because I raised this question with their FAEs. I already know what other verification people think; I wanted to get an impression of what people thought of the same methodology if it were applied to similar languages.

      --
      garethw
    2. Re:This isn't C++ or Java by Anonymous Coward · · Score: 0
      How many people on slashdot even know what Vera is?


      The people you want answering your question are the ones who know Vera, not some highschool junior who has been doing lots of nifty stuff with nasm lately.

      For those who don't know what Vera is - don't answer.
    3. Re:This isn't C++ or Java by garethw · · Score: 1

      No, you didn't read my post. That was deliberate.

      I've been using this language for about 5 or 6 years. I know what other Vera users think. But many people in my field come from more of a hardware-design background - where principles of software engineering have been less rigorously enforced. So many just take this suggestion without much alarm.

      The language itself is syntactically very similar to Java, though traditionally has used #include'd header files, just as one would in C. The only real differences are in the way the tool chain works (but then not all C compilers work the same way, do they?)

      I really wanted to see what more seasoned software developers think of this scheme. Despite the posts clamouring to the contrary, C experience is definitely relevant.

      --
      garethw
  53. Static symbols can be other things that variables by ^BR · · Score: 1

    What about

    static void init(); static void cleanup();

    This is very common to have utility functions in a .c file and to not want them cluttering the namespace. This kind of perfectly valid construct would obviously not work includin,g .c files if ther is any symbol collision. And since in C symbols are lookd up only on name and not on type or signature differing args could not save you...

  54. Re:Interface vs implementation, shared libraries, by AuMatar · · Score: 1

    Why have the .h files? Several reasons. First off- if you #include the code directly, you end up with multiple copies of functions in your executable. In big projects this can be significant space.

    Secondly, it allows you to hide implementation details. You have some things declared in the .h and some in the .c. The .c things are similar to private class members- the outside files can't access them directly. There is no way to do this with a directly include the source method.

    Third, its cleaner and easier to read. If I want to knopw what functionality a module implements, I read a .h or two. Parsing that info from the .c file would be difficult and time consuming.

    As for your other thought- why would you want to do that? Writing the class declaration takes maybe .1% of the time writing the functionality takes. And writing the declaration usually gives you time to think things through and make sure you have things the way you want them, as well as serving as documentation of the interface. A script that auto generated it would be very little to no gain, and in many ways a loss.

    --
    I still have more fans than freaks. WTF is wrong with you people?
  55. Re:Interface vs implementation, shared libraries, by crmartin · · Score: 1

    Remember that Bjarne has said from the first that a lot of C++ was designed to get away from the damn preprocessor.

  56. One big file. by TapeCutter · · Score: 1

    What is the difference between including source and one big file (except for more complex recursion and scope problems). Not much, so why not get rid of those pesky functions while you are at it and just have file:line refrences.

    You can use me as an example of point #8. As a fellow "old fart" I have come across this type of code on many occasions, it is always a hack job, usually with no statement of what it is supposed to do. They may save some time on the compile but that is trully insignificant compared to the time they will spend unraveling it when somthing goes wrong.

    The only problem with "visual programming" is that people think it is usefull for more than just skeletal code. Its great for whacking together a "normal" looking GUI and thier associated handler shells, but that's as far as it goes. I have used many compilers on *nix and Windows, (when you spend the time to know how to use it) the MSVC-IDE is hard to beat.

    UML: I have never known anyone to fight "Rational Rose" and actually come out a winner, but some pretty flow charts WITH AN ACCOMPANIYING LEDGENED can help express an idea.

    Java: Networked P-Code?

    --
    And did you exchange a walk on part in the war for a lead role in a cage? - Pink Floyd.
    1. Re:One big file. by crmartin · · Score: 1

      UML: I have never known anyone to fight "Rational Rose" and actually come out a winner, but some pretty flow charts WITH AN ACCOMPANIYING LEDGENED can help express an idea.

      Oh, absolutely. Martin Fowler's got a fine book on UML Distilled. If you stick to the notations that are in the endpapers of that book, you'll have a very useful basic notation.

      It's the arrow lawyers who spoil it for everyone.

  57. Without more detail, what is the point? by Ars-Fartsica · · Score: 1

    Everyone here thinks you are talking about C. If you aren't, this thread is pointless.

    1. Re:Without more detail, what is the point? by garethw · · Score: 1

      Not, it isn't. It was deliberate. Because few people here know what Vera is.

      It's a language syntactically very similar to C or Java.

      Traditionally, people have always #include'd header files containing class & function protoypes, just like one would in C or C++. The compiler even generates header files for you. Clearly that was the intent.

      Then one day, in all their wisdom, the vendor starts telling people to not do it that way. Some people happily follow without question. Some of us think it's bizarre and are very uncomfortable with the idea.

      I'm not advocating this method. It's being thrust upon me.

      --
      garethw
  58. modules? by Anonymous Coward · · Score: 0

    are we talking about C?

  59. Re:Interface vs implementation, shared libraries, by crazney · · Score: 1

    in header file:

    class iFoo
    {
    public:
    iFoo() = 0;
    ~iFoo() = 0;

    Bar() = 0;
    }

    in cpp file:

    class fooImpl : public iFoo
    {
    public:
    fooImpl();
    ~fooImpl();

    Bar();

    etc...
    private:
    stuff...
    }

    fooImpl::fooImpl()
    {
    stuff...
    }

    etc..

    --
    stuff
  60. Re:Interface vs implementation, shared libraries, by EsbenMoseHansen · · Score: 1

    First, let me make it crystal clear that I have always used the separate .cpp and .h files for C++ (and C) since the beginning, and still do.

    Why have the .h files? Several reasons. First off- if you #include the code directly, you end up with multiple copies of functions in your executable. In big projects this can be significant space.

    Good argument, but completely wrong :) There would be only one compile unit, and the header guards would remove any duplicates. This is why it works with templates, BTW.

    Secondly, it allows you to hide implementation details. You have some things declared in the .h and some in the .c. The .c things are similar to private class members- the outside files can't access them directly. There is no way to do this with a directly include the source method.

    If the methods are declared private, then that's it. If not, nothing prevents you from calling them, though you may have to steal the prototype from the implementation file. The only exception is global function that are declared static --- those can't be called outside the compilation unit. Not exactly a huge impact.

    Third, its cleaner and easier to read. If I want to knopw what functionality a module implements, I read a .h or two. Parsing that info from the .c file would be difficult and time consuming.

    That is very true, though the difference between two separate files and having the implementation at the bottom of the header file is rather minimal. Also, interestingly, the Java people have always inlined the entire thing in the "class" file, and I haven't heard them complaining. So maybe it is just habit (?).

    As for your other thought- why would you want to do that? Writing the class declaration takes maybe .1% of the time writing the functionality takes. And writing the declaration usually gives you time to think things through and make sure you have things the way you want them, as well as serving as documentation of the interface. A script that auto generated it would be very little to no gain, and in many ways a loss.

    Well, I write the class definition, press a key and have XEmacs generate the implementation file stub. So I don't get time to think, and I get annoyed at having to sync the two files whenever I change something. I believe it is the latter that annoys people, not the initial work, which most IDE can do automatically anyway.

    Interestingly, you didn't touch on another point: With multiple compile units, you don't have to recompile the entire thing every time you touch anything. As a KDE developer, I can certainly appreciate that!

    Also, having two classes depend on each other would certainly be harder (though not impossible).

    --
    Religion is regarded by the common people as true, by the wise as false, and by rulers as useful.
  61. Re:Interface vs implementation, shared libraries, by Hast · · Score: 1

    If you do that you can't share the header part freely in order to provide others with an easy interface to your code (while with-holding the actualy implementation). That can be extremely useful if you work on projects large enough that not everyone can work on the same part. (Ie "in the real world" code.)

    Putting defs at the top is good for defining "local" functions and variables though. Used with h-files it creates a good separation of private and public information.

    Personally I'd be very sceptic of jumping on a wagon that goes contrary to software design practices while not really having any arguments.

  62. What a linguist! :) by Chemisor · · Score: 1
    > you can push things called factors around; that
    > has nothing to do with Fowlerian refactoring

    I have never heard of anyone named Fowler, and chances are that most people who speak of "refactoring" had not either. This is not "equivocation" or "fallacy of composition", but rather the difference between the meaning of the word given to it by its creator and the one actually in general use.

    > Encapsulation does not decrease coupling in any way;
    > it simply hides non-coupled parts from one another.

    When I tell you to encapsulate your class, I imply that you would also reconsider the design of the other code that uses it to reduce coupling. Encapsulate, as in "put it in a capsule", which other code can swallow regardless of what's inside. To do this, you must define an interface and rewrite all the other code to make proper use of it. I can't see how you can do this without decoupling. I take it that you are one of those people who want everything specified to the last detail, while I am a big-picture person, who assumes that others can figure out the details for themselves. This is obviously the root of our communication problem.

    > This is why I suggested Alexandrescu-style functors

    Perhaps you could explain what they are? A google search turns up nothing except references to his book. It sounds like a good one, so I'll probably buy it some time, but you really shouldn't assume that everyone in the world has read it.

    > You should realize that statics are static variables, and that
    > static functions, despite having static in their name, are not statics at all.

    Well, there we are splitting linguistic hairs again. Human language is not that precise; words are simply references to shared concepts and if your word-concept map is different from mine (and, quite likely from many many other people), there is no need to take offence. As long as you can see what I mean, there should be no problem.

    > This is myth: static local arrays are not in any
    > way faster than nonstatic local arrays.

    Big static local arrays are most definitely slower because they are built at runtime:

    #include <stdio.h>

    int main (void)
    {
    const char* c_Strings[2] = { "Hello", "World" };
    for (int i = 0; i < 2; ++ i)
    printf ("%s\n", c_Strings[i]);
    return (0);
    }

    Try compiling this to assembly. My gcc 3.4.3 generates c_Strings at runtime on the stack, even with optimization turned on. If you make it static, this does not happen. However, speed is not really the issue here; it mainly helps reduce the size of the code.

    >> As for threaded code, I never write any
    > Obviously. You also clearly don't write libraries,
    > where you cannot guess about the nature of outside code.

    On the contrary, I write little but libraries. I just write libraries for non-threaded code, and I don't "guess" the nature of the outside code, I define it by telling the user exactly what the library is for. And it is usually not for threaded applications.

    > You do realize that the event mechanism in essentially every
    > major OS is driven by an underlying threaded model, right?

    Absolutely. It doesn't have to be this way though. In fact, to implement a good event mechanism is currently my main personal project, and I am determined to make threads entirely unnecessary in it. Theads create far more problems than they solve, IMO, and I haven't seen any good use for them that I couldn't rework into an asynchronous design. Threads and single-thread event systems really do the same thing: share the CPU between several tasks, with the former doing it at the instruction level and the latter doing it at a logical packet level.

    > As far as event driven code being faster, well, horseshit.
    > Show me non-naive test code which supports this in any way.

    I can point you to the

    1. Re:What a linguist! :) by adamscottphotos · · Score: 0

      Martin Fowler, Refactoring

      Literally the textbook on the subject.

      --
      So quit your job, pack your bags, and move on out to snow country!
    2. Re:What a linguist! :) by stonecypher · · Score: 1

      you can push things called factors around; that has nothing to do with Fowlerian refactoring

      I have never heard of anyone named Fowler


      What a surprise. He both coined the term and codified the field as its own seperate entity. Doesn't it embarrass you to argue things you don't know about?

      When I tell you to encapsulate your class, I imply that you would also reconsider the design of the other code that uses it to reduce coupling.

      You keep saying "oh yeah, I meant this other thing." No, you didn't. If that's what you meant, you've not the faintest idea what encapsulation is. Quit playing the "and by car I meant hovercraft" game. It's childish.

      To do this, you must define an interface and rewrite all the other code to make proper use of it.

      That's called rewriting, not encapsulation. "And to overhaul your car, first you have to buy a new set of doors, and paint the body." No, it just doesn't work that way. Read a book.

      I can't see how you can do this (source rewrite) without decoupling.

      Actually, it's intensely difficult to decouple and encapsulate at the same time, because the two are contrarian interests, as I explained to you two posts ago.

      I'm curious: are you able to explain what decoupling is? (braces self for something entirely random)

      Well, there we are splitting linguistic hairs again. Human language is not that precise

      No, but programming languages are. Maybe you didn't realize this, but a static is a very specific very concrete thing. We're not discussing english. If you like, you can crack the standard open and read it, since it's fairly plain that you don't know what you're on about (again.)

      As for threaded code, I never write any Obviously. You also clearly don't write libraries, where you cannot guess about the nature of outside code.

      On the contrary, I write little but libraries. I just write libraries for non-threaded code


      There's no such thing. It's really a shame to watch an amateur flail about, insisting they're not an amateur, when instead they could be learning from others.

      Big static local arrays are most definitely slower because they are built at runtime:

      I'd love to know where you picked up this curious little myth. If you compile the following code to assembly, you will be disbused of this false belief:

      int main() {
      static const int foo[5] = {0}; // lives in .RODATA
      static int foo[5] = {0}; // Compile-time allocated like any other base type
      }


      Try compiling this to assembly. My gcc 3.4.3 generates c_Strings at runtime on the stack, even with optimization turned on.

      Bwahahaha. This is awesome: you're telling me that statics are generated at runtime, and the example codce you give isn't even making statics. The reason those are generated at runtime is specifically because they're not static. Try making them static; suddenly you'll have a giant cluebulb.

      Of course, had you bothered to read TC++PL or the standard, you'd already know that statics are allocated at compile-time.

      I just write libraries for non-threaded code, and I don't "guess" the nature of the outside code

      Attempting to decide whether the user's software may be threaded is a guess. God, you contradicted yourself within a single sentence.

      I define it by telling the user exactly what the library is for. And it is usually not for threaded applications.

      Mature library authors know better than to make asinine limitations like this, and also than to expect users to notice ridiculous caveats in documentation. This is the sort of totally unnessecary restriction that makes libaries useless in real applications. Welcome to /dev/null; enjoy your stay.

      You do realize that the event mechanism in essentially e

      --
      StoneCypher is Full of BS
  63. the real reason by Anonymous Coward · · Score: 0

    It sounds like the vendor wants to make sure you can't use other vendors someday by locking you in a code marriage of some type. Keep it seperate, there is no good reason to mess the code together.

  64. That's whack by etresoft · · Score: 1

    Have you considered the possibility that both your tool vendor and lead developer don't know what they are doing? Any questions regarding compilation time are simply irrelevant. The only reason someone would include a source file is because they can't get the project to link with either a library or object code. Pretty much the only way that would happen is if either the tool vendor or the lead developer (or both) don't know what they are doing. The logical suggestion is to just link a sample app yourself and show them that it can work after all. However, that would probably offend the lead developer and get your fired or shunned.

  65. Stupid Question by Frankie70 · · Score: 1

    Is this a stupid question or what?

    The conventional argument I recall for using header files, and incremental compilation, is that it's faster to use a makefile and conditionally build only those files that have changed


    No it isn't. Header files doesn't help in incremental compilation. Atleast not in C.

    The reason for header files is
    1) Function prototyping. Otherwise, you may have
    to prototype functions in all source files
    2) For structure definitions. Otherwise, you may
    have to do it in all source files.
    3) #defines. Same reason

    and so on & so forth.

    Is there something I am missing here?

    1. Re:Stupid Question by garethw · · Score: 1

      The reason for header files is 1) Function prototyping. Otherwise, you may have to prototype functions in all source files

      Not true. They're saying the ENTIRE source code base should be #include'd in a tree-like structure, down from the top level file.

      You don't need a prototype in each source file because the actual definition is right there, #included hierarchically.

      Listen, people, I'm not advocating this method. I stated (pretty clearly, if you ask me) in the question that I think it's "abhorrent". But it's being thrust upon me and I'm trying to figure out if there are really advantages to it.

      --
      garethw
    2. Re:Stupid Question by mvdw · · Score: 1
      From what I understand, you are not "compiling" in the traditional sense, but rather more-or-less running a simulation. The compilation is the goal; what is done with that compilation is pretty much thrown away (AFAIU), so it makes sense to reduce compilation times. If you think about it in this way - running a simulation rather than doing a compilation, it makes more sense. Compare, for example, "compiling" a SPICE program to compiling a C program.

      In that case, you should be doing whatever you can to minimise compilation times. If that includes doing something abhorrent (and I admit, it is pretty abhorrent), then so be it.

  66. Parallel Make? by ufnoise · · Score: 1

    Using the suggested new system, how would parallel make work? Parallel make on a uniprocessor or multiprocessor machine allows multiple compilation units to be compiled simultaneously. While one process is waiting on file I/O, the other process can be chugging away on another compilation unit. In addition, only compilation units depending on a changed header will need to be recompiled.

  67. Re:Interface vs implementation, shared libraries, by garethw · · Score: 1

    Personally I'd be very sceptic of jumping on a wagon that goes contrary to software design practices while not really having any arguments.

    Precisely, sir.

    A curiously large proportion of responses seem to think I'm advocating this approach. I'm not; it is being thrust upon me.

    --
    garethw
  68. But what they're advocating could apply to C by garethw · · Score: 1

    But it's not that different.

    The language itself is syntactically very similar to Java, but has traditionally used header files as one would in C. Then one day, the vendor starts telling people not to do it that way.

    What is different is the tool chain. But that's not really the language per se. Not all C tools are used in the same way either. SO I think the comparison is still valid.

    But what they're advocating would still work in C, which is why I posed the question that way. Many replies have latched on to the idea that you'd have to have function prototypes in every source file, but that's not true. The entire app ends up being one translation unit, so there ARE no externals; it's all right there in the output of one pass of the pre-processor.

    I'm not saying it's a good idea. I really, really don't like it. But it works better than most of the replies here have assumed.

    Interestingly, this language actually uses a modified cpp for pre-processing.

    --
    garethw
  69. Re:Interface vs implementation, shared libraries, by garethw · · Score: 1

    But you don't get need duplicate defintions.

    You end up with the entire code in one compilation unit (if that's the correct term). There is no need for function or class prototypes, or for externs - the implementation is right there in the #include'd source hierarchy.

    Bizarre? Yeah, I agree. But what would you do if your tool vendor one day tells you to do something you think you believe you will later regret?

    --
    garethw
  70. Sounds like Vera by EdA · · Score: 1

    Sounds like you're using Vera because 'e' does not allow separate compilation - but then I've never used SystemVerilog.

    You probably should have asked at http://www.verificationguild.com.

    We've never had a problem with the "single compilation" when using Vera - although we tend to compile "the environment" as one compile and the testcase as another. There can be issues (you have to generate a master header file, forward referencing certain classes, etc.). /Ed

  71. I do this with C and other languages. by Anonymous Coward · · Score: 0

    I've been doing this for over a year. I have a few projects that are 5000+ lines of code.

    I use a 10 MB memory file system for /work and custom editors that save automatically. Then I have a sync_work.sh script that looks like this:
    $ cat sync_work.sh
    #!/bin/sh

    while true
    do
    day=`date +%A`
    p=/home/gps/src/automated_backups/$day
    mkdir -p $p
    cd $p
    d=`date +%s`
    tar -cPf work_$d.tar /work
    echo "done with $day $d"
    #60 * 5 = 300
    sleep 300
    done

    I compile the file(s) with the many #include's using gcc -pipe.

    Overall it saves me time when compared to the traditional techniques. The only things to watchout for would be global variables, or static functions. I haven't found this to be a problem in practice.

    -GPS

  72. Re:Static symbols can be other things that variabl by Anonymous Coward · · Score: 0

    These are static functions, not variables, and the original posters didn't make any comment about whether or not they were good ideas.

  73. Re:Interface vs implementation, shared libraries, by Mysticalfruit · · Score: 1

    The problem with your formula is that it prevents you from taking your implimentation and creating a shared library out of it.

    Seriously. Let's just say your tasked with creating a graphical toolkit. You go off and in 3 months you've created a masterpiece. You've got everything! Sliders, icons, buttons, rulers, progress bars, menus, text windows, labels, etc.

    Now, lets say you take your graphical toolkit and create your own "copy" program. So, you'll need a couple text boxes and/or some open/save dialogs, some labels, maybe a button or two and a progress bar.

    What makes more sense. Use header files and have the compiler link against a graphical toolkit shared library OR have the compiler compile thousands of lines worth of your code you'll never use and statically link it into your executable?

    --
    Yes Francis, the world has gone crazy.