“Only headers” coding convention

Posted by (twitter: @aki_koskinen)
April 20th, 2012 2:40 am

This next Ludum Dare is my first one. I have been doing games for years now and I know from experience that you can only achieve so much in two days (in my case, that’s not much). So I’m looking for short cuts wherever I can find them.

I’ll be using C++ for coding since I’ll be using the Proton SDK. I’ve been using it lately a lot for other projects so it’s fresh in the memory. C++ is a great language in many ways (one of them being its portability across platforms) but there are some features that are more a hindrance than an advantage. One of them is the preprocessor which C++ inherited from its C roots. With the help of the preprocessor and the #include directive especially it’s usual to divide classes into a definition and declaration. The definition goes to a file ending with .h and the declaration (or implementation) goes to a .cpp file (the postfixes might vary slightly from case to case but these are the usual ones).

This is useful for example if you are developing a shared library. You compile the .cpp files in to the library. You collect the .h files and submit them with the compiled library to the users of the library. The users can now find the interface of the library from the .h files and code against it. Then they link against the compiled library and everything is good. The users don’t know about the implementation details of the library since they don’t need nor get the .cpp files.

The extra burden delivered to the developer with this file separation is that the interface in the header file must off course always match the implementation in the .cpp file. Change one and the corresponding method signature needs to be changed in the other file too (this .h/.cpp file separation is so badly against the DRY principle that it makes my head hurt – constantly). Miss that and you get a compilation error. Luckily the error messages produced this way are usually so much descriptive that it’s easy to fix them. But it’s still extra work. Tools off course can help a bit in these situations if your IDE happens to have a suitable refactoring feature.

I struggle with this problem every now and then. Now for Ludum Dare I decided to try something different. Since I’m not developing a shared library here and the code I’ll be writing will probably not be used elsewhere (at least without some heavy modifications) I can mess around with it as much as I like. For this purpose I have developed a coding convention that I shall call “only headers”. All of the code that I’ll be writing will reside in C++ header files only. So for each class the definition and the declaration will be bundled together to a single file. This way the signatures of methods are only written to a single place and whenever a method signature needs a change it will be enough to modify it in one place.

All of these header files will be included directly to the main.cpp file. The inclusion order needs to be correct so that the compilation succeeds. This approach is essentially the same that if you would write all the code to a single file. That file would probably grow several thousands of lines long so it gets hard to navigate in it. By separating the code to multiple files the navigation problem should decrease.

Now the obvious problem with this approach is off course that the compiler (and preprocessor) needs to always parse through all the code that there is in the project. But I’m thinking that the amount of code will not grow too big during the 48 hours of the LD event. But I can’t know that for sure right now. I guess I’ll find out during the week end how this works out. I’ll be reporting the experience after the event.

If you have any experience from this kind of approach, any tips or traps to avoid do share them in the comments.

Tags: , , ,

9 Responses to ““Only headers” coding convention”

  1. vrld says:

    This approach will drastically increase build times. Image you change one of 10 source files and want to test your changes. Using multiple cpp files and linking the object files after compilations means that you only have to recompile the code for the file you just changed. If on the other hand you put everything in header files, changing one file will result in *all* the code to be recompiled, taking 10 times more time than the source/header method.

    Don’t do it.

  2. And the question remains, while C++ is great and everything, why not use something more streamlined and made for creating things quickly, like Flash or haXe etc which would save you a lot of time and grunt work.

    • gormio says:

      Perhaps some other time when I have some knowledge about such tools. Since I know zero about Flash or haXe or other such things and a lot more about C++ I’ll choose a tool that I’m familiar with.

  3. mcc says:

    This is actually something I used to try to do in my C++ code, I was only writing small programs at the time so I didn’t care about compile time. I ultimately abandoned it because of this problem: Say you have a class A and a class B which mutually refer to each other. Like maybe class A has a A::create_from_b(B *b); method and B has a B::create_from_a(A *a) method. The only way to do this in C++ is to define A first, then B, then define A::create_from_b and B::create_from_a outside of the class {} definitions. (You can forward declare classes in C++ but only if you just hold pointers to them, if you’ve forward declared you can’t access any fields or methods of the class). You will also be required to declare any static variables of classes outside of the class {} somewhere.

    You then run into a larger problem. Let’s say you define even one method or static variable outside of the class {}. If you place this definition into the header file, then, well– you say you only include the header file tree from the main.cpp file? That had better be the case because otherwise your method/static var declaration will be copied into all cpp files which include your header tree, and you will get a linking error with a duplicate symbol.

    • gormio says:

      Yep, good points. I’ll try to avoid cyclic dependencies as far as possible. Will see how well – or bad – this will go.

      And yes, in order for this to work all the headers can only be included once – let it be main.cpp or any other place. Basically the only #includes that can be in the header files need to point outside of this codebase. They can’t include each other.

      • mcc says:

        I believe you can multiple-include your megaheaders as long as no static class variables or non-static normal variables are declared, and all functions within the megaheaders are either inside of a class {} or static/inline.

  4. sdwil2k5 says:

    I used this method on the first generation of my game engine which was mostly hacked up and bolted together NeHe tutorials (back when NeHe would blog endlessly about his crappy day job, lol). I just had a quick look through the 10yr old code (yuck! who coded this ugly mess?) and here’s a few things I noticed.

    – I had included all my .h files into a master ‘include.h’ file and included this file only into my master .cpp file (I only had one that contained my WinMain function). This meant that I didn’t have to scroll through 3 pages of includes before any code was visible.

    – The code was easy to navigate. Rolling up to the top of a file to view/edit class structure is quite intuitive and quick.

    – Because I had only one .cpp file there was no need for include guards. I guess if using multiple .cpp files, placing one guard only on the master ‘include.h’ file would suffice.

    – I placed stand alone functions into their own header files also, so that the single .cpp file didn’t grow too large.

    – All of my forward declarations were placed into their own header and this was included immediately after my 3rd party includes.

    You probably have a good handle on all this but just thought I’d share my experience for what it’s worth.

    Good luck.

Leave a Reply

You must be logged in to post a comment.

[cache: storing page]