CppCoreGuidelines icon indicating copy to clipboard operation
CppCoreGuidelines copied to clipboard

SF.5: an include of an interface should be relative

Open DanielKriz opened this issue 3 years ago • 9 comments

Although it is possible to include an interface as a library (or through the search path), it is much more common and standard using #include "foo.h" for interfaces of classes, than #include <foo.h>.

It is also supported by SF.12: #include "foo.h" // A file locally relative to foo.cpp in the same project, use the "" form

Therefore I think it should be changed to relative import.

DanielKriz avatar Jul 24 '22 09:07 DanielKriz

it is much more common and standard

Citation needed.

Using #include "foo.h" only makes a difference if the code has headers and sources files in the same directory, so isn't useful for a project structured as:

libfoo
├ include
└ src

I don't think this change is as obviously correct as you suggest.

jwakely avatar Jul 25 '22 12:07 jwakely

I have to admit, that I have been only working on projects that didn't use include directory. So thanks for pointing that out.

I am going to try to look for some source to back my statement. But I haven't through about the include directory.

edit: I would also like to point out, that using include directory usually comes with using some kind of makefile/cmake or a bit more complex way of using compiler. Therefore I think that examples shown in guidelines should be as simple as possible. Which is header, that is stored locally, next to the source file.

DanielKriz avatar Jul 25 '22 14:07 DanielKriz

I couldn't find anything trustworthy enough to support my claim "that it is much more common and standard".

But I still think, that it should be changed to #include "foo.h" as it is a bit more bare bone example, that does not expect you to setup some kind of include directory. If you are using include directories, then you probably understand that #include "foo.h" can be changed to #include <foo.h> with include directory.

But for newbies to the language it could be misleading as they could easily confuse it with some system library.

DanielKriz avatar Jul 25 '22 14:07 DanielKriz

usually comes with using some kind of makefile/cmake or a bit more complex way of using compiler.

If you're only compiling toy examples with one or two source files, the guidelines don't really matter anyway.

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#innot-non-aims

"These guidelines are not intended to be a substitute for a tutorial treatment of C++. If you need a tutorial for some given level of experience, see the references."

jwakely avatar Jul 25 '22 14:07 jwakely

Yet even on complex project you don't really have to use the include directory. (But it is convenient for some use cases, for example if you are including some other file (bar.h) than interface)

Yes it is mentioned that "The rules are not intended to be minimal or orthogonal.". And I have to admin that your argument is really good. But from my point of view the #include <> for interfaces are a special case of #include "". But that may be just a matter of preference (one or another). So it is probably up for a discussion. But hey, It is safe to say that you are the more experienced here, so if you think, that this suggestion does not make sense, then it probably doesn't.

DanielKriz avatar Jul 25 '22 15:07 DanielKriz

I know Qt uses in-place headers; however, personally I have found it's best to always separate out my headers into public and private includes:

includes // public interfaces, definitions, etc
includes-private // private interfaces, definitions, etc
source

All-in-all, they're probably about equally common and which methods used is based on the desires of the core devs/maintainers. Guidelines should support both methods equally as a result.

BenjamenMeyer avatar Jul 25 '22 16:07 BenjamenMeyer

I know Qt uses in-place headers; however, personally I have found it's best to always separate out my headers into public and private includes:

includes // public interfaces, definitions, etc
includes-private // private interfaces, definitions, etc
source

But that is used like #include <foo.h> in both cases, right?

All-in-all, they're probably about equally common and which methods used is based on the desires of the core devs/maintainers. Guidelines should support both methods equally as a result.

Well I could change my pull request to something like #include <foo.h> // or "foo.h" if they are both in one directory, but I don't think that is done that way anywhere else in the guidelines. (funny thing, #include "foo.h" is located in one place and that is SF.12)

DanielKriz avatar Jul 25 '22 17:07 DanielKriz

I know Qt uses in-place headers; however, personally I have found it's best to always separate out my headers into public and private includes:

includes // public interfaces, definitions, etc
includes-private // private interfaces, definitions, etc
source

But that is used like #include <foo.h> in both cases, right?

Correct because I don't do inline headers - they're never co-located. Instead, I treat them as API contracts (internal or external, with external often being in another repository). But that's me - it's a layout I've found helps minimize (a) projects improperly pulling in files from other projects and (b) helps enforce API contracts (API/ABI). It does force a little more work, so it's not for the lazy; but in the process things are more disciplined and better communicated. Any how...that's getting off-topic for here.

All-in-all, they're probably about equally common and which methods used is based on the desires of the core devs/maintainers. Guidelines should support both methods equally as a result.

Well I could change my pull request to something like #include <foo.h> // or "foo.h" if they are both in one directory, but I don't think that is done that way anywhere else in the guidelines. (funny thing, #include "foo.h" is located in one place and that is SF.12)

The real difference between #include <> and #include "" is that the first only checks paths listed/configured for the include - typically the -I compiler parameters; while the second also includes the relative paths (., ../, etc) with respect to the file being worked on.

Honestly the #include "" version can be much more confusing. yes, it's convenient but what happens when the files get moved? More things tend to break. Further it leaves more paths for the compiler to search which can mean larger compile times (the little things add up). It's also easier to break things in IDEs since the IDE and the compiler have to both agree on how to interpret the directories and if they don't debugging can become a nightmare.

So all-in-all, the #include<> version while requiring a little more effort on the part of developers does yield a better overall experience. I'd personally advocate that #include "" should go away or at least be used for only de minimis cases, but I'm probably in the minority there, and as I mentioned earlier - some rather large open source projects use #include "" extensively.

BenjamenMeyer avatar Jul 25 '22 18:07 BenjamenMeyer

Honestly the #include "" version can be much more confusing. yes, it's convenient but what happens when the files get moved? More things tend to break. Further it leaves more paths for the compiler to search which can mean larger compile times (the little things add up)

Only, if you don't use the syntax for relative paths. Otherwise it should be the other way round, because the very first location the compiler looks at is the right one.

MikeGitb avatar Jul 25 '22 19:07 MikeGitb

It has been merger, therefore I am closing this issue, thank you everyone for great discussion.

DanielKriz avatar Aug 08 '22 20:08 DanielKriz