Friday, June 02, 2006

Why not #inlude #include into #include?

I have an empirical rule of thumb, which I bring to all my C++ projects:

Do not #include other #includes in header files.
The only thee excuses are:
  • Inheritance: #include a base class to inherit from it.
  • Composition: #include a class to use it as a value member object.
  • Standard types: #include STL and standard headers for standard types used in class declaration.

  • In all other cases use forward declarations.


    It sounds straightforward, even trivial. But somehow I find myself explaining it again and again to C++ programmers, even to quite experienced ones.

    So, why not include extra #includes in header files? Here is my "short answer":

    Each include introduces a dependency. Extra unnecessary includes introduce extra ways many unnecessary dependencies. The application soon snowballs to a monolithic blob of well pressed spaghetti code, where everything depends on everything.

    The order of .h files suddenly matters: sometimes it magically works because of the hidden includes. But this white magic becomes black magic. Someone removes an #include because noone seems to use it. This innocent change breaks things 5 header files away, it doesn't complile any more. So scared programmers don’t dare to change the order of #includes.

    Any touch in any include file results in rebuilding the whole application. Nowadays the compiling time doesn't concern me (if it concerns you, check out Xoreax IncrediBuild). But the fact that the whole system has been recompiled concerns QA folks: the files now are not binary equal so all bets are off and they got to retest the whole application!



    Code reuse, refactoring, and unit testing become almost impossible. Every class drags behind the entire code base.



    For long answer, I refer you to "Large Scale C++ Software Design" by John Lakos.

    The "rule of thumb above is a simple and powerful empirics to keep C++ code dependencies under control.

    This is the way I teach C++ programmers not to #include #include files into #include files. What do you think? Am I doing something right? Leave your comments, please help me do better.

    AddThis Social Bookmark Button

    1 Comments:

    At 6/05/2006 02:00:00 PM , Blogger Anatoli Beliaev said...

    I agree, but I would like to note: please don't remove ALL #includes from your header files now. Keep your header files self-sufficient. The reasons mentioned by Dmitry are not just "excuses", they are perfectly valid reasons. If you don't include necessary header files, you increase chances of #include ordering problems. The word "self-sufficient" does not mean "independent" here, it means "taking care of its own needs". Ideally, if you have MyHeader.h file, then a .cpp file containing only
    #include "MyHeader.h"
    should compile.

    Also, the following tips can help you to get rid of unnecessary or unwanted dependencies:

    1. If you have a header file that changes often and you want to isolate depending components from re-compilation, consider building "compiler firewalls" using the Pimpl idiom (http://www.gotw.ca/gotw/028.htm) and the dependency inversion principle.

    2. Please think twice before adding a private member function to a class. Privates are inaccessible, but they are still visible, so any dependent components may be re-compiled when you change private members. If the new function does not depend on any class members, it should probably be a free function in .cpp. Don't forget to make it local: use namespaces (perhaps unnamed) or the old-fashioned "static". Even if the function depends on class members, consider passing these members as function arguments. This is not only a trick to avoid re-compilation. It may not look obvious, but private members ARE parts of class interface, so changing private members influences dependent components.

     

    Post a Comment

    << Home