In my opinion, if a C or C++ formatter reorders #includes, that is a bug in the formatter. Remember, #include is just a simple copy-paste macro. Reordering #includes changes the source code in a non-trivial way. Over the years I have seen many headers - even in standard headers that shipped with the compiler - that had a variety of side-effects and even caused errors if the order were any different. Just a simple using namespace std; in your header makes reordering deadly. Or forward declarations. Should you write your headers like that? No. Does it happen in the wild? Yes, all the time.
We had some wonderful build issues related to this at my last job.
There was a super old header that #defined a few key constants. This header was usually #included into just about every compilation unit in the company. Sometimes these constants were needed in a protobuf-like layer, so we would end up generating code with enums that had the same name as the #defined constants.
For example:
old.h:
#define RED 1
#define BLUE 2
proto.hpp:
enum { RED = 1, BLUE = 2 };
im_trying_to_do_my_best_here.cpp:
#include <iostream>
// .. a million headers ..
#include <enterprise_fun_time.hpp> // includes <old.h>
// ... a million more headers ...
#include <proto.hpp>
Compiling the above gives you an error message that "enum { 1 = 1, 2 = 2 }" is just silly. Fixing this was a trick sometimes; it’s hard to trace where transitive includes are coming from. This kind of issue also more common than I’d like to admit :).
I personally like that clang-format rearranges headers. Though yes, it can break your build (or even change your program!). I think encouraging C/C++ developers to do their best to have order-independent headers is a Good Thing™. I suppose it could always be turned off with the IncludeBlocks option in clang-format.
Right, I mean some headers are designed with the use of side effects in mind, like
#define _GNU_SOURCE
#include <string.h>
I guess you’re supposed to #undef it afterwards to clean up your state, but most people don’t do that. IIRC Python sets _GNU_SOURCE globally in pyconfig.h.
The issue isn’t limited to C: changing the import in Python can have even worse arbitrary side effects. Python formatters may do that too IIRC.
In my opinion, if a C or C++ formatter reorders
#include
s, that is a bug in the formatter. Remember,#include
is just a simple copy-paste macro. Reordering#include
s changes the source code in a non-trivial way. Over the years I have seen many headers - even in standard headers that shipped with the compiler - that had a variety of side-effects and even caused errors if the order were any different. Just a simpleusing namespace std;
in your header makes reordering deadly. Or forward declarations. Should you write your headers like that? No. Does it happen in the wild? Yes, all the time.We had some wonderful build issues related to this at my last job.
There was a super old header that
#define
d a few key constants. This header was usually#include
d into just about every compilation unit in the company. Sometimes these constants were needed in a protobuf-like layer, so we would end up generating code withenum
s that had the same name as the#define
d constants.For example:
old.h:
proto.hpp:
im_trying_to_do_my_best_here.cpp:
Compiling the above gives you an error message that
"enum { 1 = 1, 2 = 2 }"
is just silly. Fixing this was a trick sometimes; it’s hard to trace where transitive includes are coming from. This kind of issue also more common than I’d like to admit :).I personally like that
clang-format
rearranges headers. Though yes, it can break your build (or even change your program!). I think encouraging C/C++ developers to do their best to have order-independent headers is a Good Thing™. I suppose it could always be turned off with theIncludeBlocks
option inclang-format
.It sometimes amazes me that we’ve ever managed to make anything work at all.
It is no surprise that (spoiler) include order has side effects. Will C++ modules be different?
The surprise is meant to be the subtle nature of the side effects and also the fact that
clangclang-format does it automatically.clang-format, not clang.
Right, I mean some headers are designed with the use of side effects in mind, like
I guess you’re supposed to
#undef
it afterwards to clean up your state, but most people don’t do that. IIRC Python sets _GNU_SOURCE globally inpyconfig.h
.The issue isn’t limited to C: changing the import in Python can have even worse arbitrary side effects. Python formatters may do that too IIRC.