Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SF.1: Default convention for C++ header files should be .hpp (matching .cpp) #686

Closed
GiovanniDicanio opened this issue Aug 19, 2016 · 24 comments
Labels

Comments

@GiovanniDicanio
Copy link

Having a specific “.hpp“ extension (like Boost does) for C++ headers (matching the “.cpp“ extension) makes the C++-specific nature of the header very clear.

Moreover, editors and tools can understand simply looking at the extension that it's a C++ header instead of a pure C header. In this way, rules like this one requesting a “magic string“ to clarify that an header is C++ (not C) are made useless:

"The “-- C++ --” string on the first line is there to tell Emacs that the source file is a C++ file, not a C file (Emacs assumes .h files are C files by default)."

The “.h” extension should be used for header files that contain pure C declarations, and are intended to be read by C and/or C++ (like <stdio.h>, <Windows.h>, or custom headers exposing pure C interfaces). The “.hpp” extension should be used for header files that contain C++ stuff (e.g.: class declarations and/or inline implementations) and are not intended for C.

@GiovanniDicanio GiovanniDicanio changed the title SF.1 - Default convention for C++ header files should be .hpp (matching .cpp) SF.1: Default convention for C++ header files should be .hpp (matching .cpp) Aug 19, 2016
@galik
Copy link
Contributor

galik commented Aug 19, 2016

I've never used .hpp for headers, in fact I still don't. But I do think the rationale has merit. One day I might convince myself to switch.

@grahamreeds
Copy link

Does it really matter?

The standard library doesn't have extensions and neither does this library
now. I feel it is another of those "As long as you are consistent" things.

Strangely I use .h on Windows but on Linux I use .hpp. I have never
programmed C++ on a Mac so I don't know what I would use there. Maybe I
would use .hxx.

GR

Sent from my Nexus 5.

On 19 Aug 2016 6:06 p.m., "Galik" notifications@github.com wrote:

I've never used .hpp for headers, in fact I still don't. But I do think
the rationale has merit. One day I might convince myself to switch.


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
#686 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AEy9nDrA01faoeD8SQZYMBL3G2dVyoOUks5qheKigaJpZM4JomHI
.

@GiovanniDicanio
Copy link
Author

It does really matter not suggesting ".h" as the "good default" for C++
headers.

As .cpp is suggested as default for C++ sources, .hpp should be suggested
as default for C++ headers.

Giovanni

Il sabato 20 agosto 2016, Graham Reeds notifications@github.com ha
scritto:

Does it really matter?

The standard library doesn't have extensions and neither does this library
now. I feel it is another of those "As long as you are consistent" things.

Strangely I use .h on Windows but on Linux I use .hpp. I have never
programmed C++ on a Mac so I don't know what I would use there. Maybe I
would use .hxx.

GR

Sent from my Nexus 5.

On 19 Aug 2016 6:06 p.m., "Galik" <notifications@github.com
javascript:_e(%7B%7D,'cvml','notifications@github.com');> wrote:

I've never used .hpp for headers, in fact I still don't. But I do think
the rationale has merit. One day I might convince myself to switch.


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#686
issuecomment-241075599>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/
AEy9nDrA01faoeD8SQZYMBL3G2dVyoOUks5qheKigaJpZM4JomHI>
.


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
#686 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AEeal6VftT4kUBl-Aa2N1dP-Zn38PfiTks5qhurngaJpZM4JomHI
.

@MikeGitb
Copy link

While I'm personally always using .h (mainly because it is the default in my IDE) I agree, that having a more or less official and distinct c++ header extension would be nice and .hpp would certainly be the prime candidate for that.

@BjarneStroustrup
Copy link
Contributor

We don't feel that we should suggest a major change to status quo, and .h has been used for decades

@GiovanniDicanio
Copy link
Author

GiovanniDicanio commented Aug 26, 2016

To add another data point to this conversation, this is a post I wrote in a private thread discussing .hpp for C++ headers, that I thought might be appropriate to repost here:

When you have source files, do you differentiate between their nature and their content being C or C++, don't you? This is why we have .c and .cpp distinct extensions. So, it makes sense to apply that to headers as well.

In fact, if you don't clearly communicate the content of the header using a proper extension, you end up with magic strings embedded in comments in the headers like the aforementioned Emacs example of the Clang coding guide.

I do prefer a clear extension communicating the content of the header being C++ and not C, vs. a magic string embedded in the header comments.

I worked on a project which was developed in C++, and we used a third-party library for linear algebra that exposed both a pure C interface and a C++ interface. The library authors wanted to make it possible to use their library in both C and C++ projects.

So, if you wanted to use the C interface of the library, you included e.g. "Vector3.h", which was a C header and you got something like a vec3_t C structure typedef with C functions like:

vec3_t* Vec3_Add(vec3_t* result, const vec3_t* v, const vec3_t* w);

And if you included "Vector3.hpp" you got a nice Vec3 C++ class, with convenient overloaded operators, etc., such that you could use the standard clear "v+w" notation for summing vectors.

To me, it's really subjective to pick an extension for C++ sources among .cpp vs. .cc vs. cxx (I'm used to .cpp since I started with Visual C++ 6, and that was the default; but I have no problem with other extensions, assuming consistency in a given project).

But once you've picked an extension for C++ sources, I think it makes sense and is good to choose a correspondent symmetric extension for C++ headers, e.g.:

.cpp, .hpp
.cxx, .hxx
.cc, .hh

And that matches the C symmetry of .c for C source files and .h for C headers.

My 2 cents,
Giovanni

Consistency is important in projects, so if you are working on a project already using .h for C++ headers or whatever other extension, I agree to continue following that particular extension in that project for the argument of consistency.

But for new projects, IMO it's better to suggest a specific C++ extension for headers, considering the elements I tried to expose during this thread.

Thanks.

@BjarneStroustrup
Copy link
Contributor

You made a suggestion to recommend your favorite convention. You gave a reason. However, most people (as far as I can tell, the C++ community is HUGE) have not found the various arguments for .hpp compelling eventhough your convention and the arguments you offer have been known and used for at least a couple of decades.

I prefer not to mess with status quo unless there is a significant chance of success and the issue is among the ones that I think would give the most benefits to the community.

The arguments for a change must always be stronger than for status quo because it takes work, efforts, and resources to make a change.

I have worked on projects that used .h, on projects that used .hpp, and on projects that used .H. I did not notice the choice of suffix to be among the significant problems or advantages. So, I prefer to spend my efforts on other things.

Boost is a nice and prominent collection of libraries, but it is just one library. Boost's use of .hpp is not in itself a proof of anything beyond "something like this can work", and we already knew that long before Boost.

The committee decided against using suffices for headers partly to avoid having to make a choice among suffices and partly because there is no guarantee that a header is a text file. Different encodings of the header information may use different suffices when stored as files. This becomes interesting/relevant once we move to a world of modules. There might be different module encodings, so we are likely to use import and export directives that do not use suffices (with a mapping to files with suffices behind the scenes in the implementation). Unfortunately, modules are not yet sufficiently widely available for us to base the Guidelines on them, but it may be time to start thinking about guidelines for a transition to modules. I'd love to se a rule "Use mudules, rather than directly #including headers."

@johnthagen
Copy link

A small bit of data on this topic. I've been researching the topic as it's something I have been mulling for a while:

  • This StackOverflow post that advocates for .hpp has 300 upvotes (and provides several concrete reasons)
  • Catch, a popular open source framework with 4000+ stars on GitHub, uses .hpp

@faheel
Copy link

faheel commented Jul 5, 2017

@johnthagen I too advocate for using .hpp for C++ headers, but as @BjarneStroustrup mentioned above, the data provided is still too small to consider a change.
To really bring the change we desire, I believe that all of us who support the use of .hpp over .h should put in some more effort, and probably start a big campaign that attracts the majority of the C++ community and educates them on why we should all be using .hpp for C++ headers ... but doing so would require a lot of time and effort, and aren't there more important things for us to work on?
Moreover, the guidelines recommend the use of .h and don't enforce it,

[...] consistency is more important, so if your project uses something else, follow that.

so you're free to use whichever you (and I) prefer 😉. Maybe over time, by small collective efforts such as yours, @GiovanniDicanio's and others, .hpp would become the norm. Until then, all I request for is that .hpp be added among the other listed alternatives (such as .hh).

@jdgarciauc3m
Copy link

I believe the common is by far to use .h for headers.

Once you enter in the .hpp for C++, sombody will suggest .tpp (or templates), .inl for inline definitions and so on.

Keep it simple!

@phillipjohnston
Copy link

phillipjohnston commented Jul 17, 2017 via email

@GuillaumeDua
Copy link

I'll join @phillipjohnston. It makes sense to use extensions .c and .h for C files,
.cpp and .hpp for C++ files.

@jdgarciauc3m I really doubt that will encourage or lead to other extensions.

@CVipulS
Copy link

CVipulS commented Jul 17, 2017

Does mixed C/C++ project mean including iostream from .C files? Will .hpp make iostream and cout significantly more popular than stdio and printf within .cpp files? When differentiation is so badly needed, early adoption of modules proposal might be better alternative.

@phillipjohnston
Copy link

phillipjohnston commented Jul 17, 2017

I work on embedded systems, so mostly when it's mixed C/C++ it's just dealing with large portions of (probably legacy) C code. Not from the sense of using C++ constructs from .c files. Depending on the project's size and momentum, not all of the code may be compiled with a C++ compiler.

I also am not going to die on any hill regarding header file type conventions :). I'm just providing an example of how using the same header file type (.h) for two distinct languages can be very confusing. Especially when the languages can sometimes, but not always, inter-operate.

@jdgarciauc3m
Copy link

The rationale for using a different extension for C++ source files is that some tools will easily recognize if the translation unit is C or C++. This is why we use .cpp (or some others like .cxx). The most common case is a build system determining if the C or the C++ compiler should be used.

This does not apply to header files, as they will be included (directly or indirectly) from some source file (i.e. some .cpp file).

@GiovanniDicanio
Copy link
Author

GiovanniDicanio commented Jul 19, 2017 via email

@jwakely
Copy link
Contributor

jwakely commented Jul 19, 2017

Obviously there's no convention that will please everybody. It seems to me that that this discussion is not going anywhere.

@GiovanniDicanio
Copy link
Author

GiovanniDicanio commented Jul 19, 2017 via email

@fekir
Copy link
Contributor

fekir commented Mar 14, 2018

I would like to add my opinion to this discussion, even if it is marked as closed, and hope that some things might get reconsidered.

The first thing I do not like in the reasoning is that this guideline is proposed because of legacy.
With this reasoning we could argue that a lot of guidelines, for example all those that mentions constexpr, are wrong because before c++11 we did not have constexpr and therefore we should not use it.

The second issue is that some guidelines state that C and C++ are different languages.
Different languages means different rules, different standard libraries, different practices and so on.
Those two languages only have a small common subset, and should therefore get treated differently in most cases.

Telling people to use c filenames seems to go against those rules, after all that's the reason why we use .cpp, .cc or other file endings but definitely not .c for c++ only source files.

The second think that I dislike is that there are some advantages by using a different file ending, but those are not mentioned.

As already mentioned, clang could take advantage of it without using internally magic strings, but other tools too of course.

file for example:
Every time I have a C++ only header file, and I know its c++-only because it has class definitions, templates, namespaces, includes the standard library, and no strange ifdef's, file tells me that it is a C header file.
Of course find and other tools will not parse the file entirely for determining if it is a c++ file or not, and we should not expect that.
Since a file name is often taken into account when determining the mime-type of a a file, using a different extension would help.

QtCreator (an IDE) on most header files tells me that it is unsure if he should parse it as c or c++ header file, which is annoying.
Again, using .hpp instead of .h would help.

Other static analyzers, (most of C++ static analyzers also works on C code), could, like clang take advantage of that.

And there are probably other use cases (different conventions for file editors, mime type registration in the OS, ...) that I did not think of.

Another couple of considerations:

Modules are not really an option/alternative.
There are a lot of old and new libraries that want to be compatible on old platforms (many are even pre-c++11).
Using modules is a breaking change, it would require at least c++20, which is a huge change in tooling, especially in embedded systems.

Using .hpp instead of .h is backwards compatible to probably the oldest and most esoteric compiler.

Of course being consistent is important, but IMHO it is also relatively easy to change this convention even in a big codebase.
In many old codebases constants are not constexpr, but for that reason we are not going to tell people not to use constexpr because they should be consistent.
It is completely fine to sprinkle constexpr here and there and make the current codebase better.
One day (the day after, one week, five years) using constexpr in the codebase for constants will be common enough to be the rule and not the exception.

Similarly the same can be done for filenames.
Just rename the files.
If something breaks, it is at compile time, and the compiler will tell you exactly where it included the file and where you need to update the code in case you missed it.
It is easy to automate most of the work: use rename and grep, compile and eventually fix the corner cases.

If the use-case is more complicated, because some (but not all) headers are really ment to be used in C projects too, then you already have the problem that you need, every time you open a header file, to understand if it is a C or C++ header file, and if it compiles with both compilers when you make a change.
If the conclusion is that a particular header file should not get compiled with C anymore, even if it looks like a C file because all signatures and declarations seems to be C compatible, this information is lost when someone else needs to work on the file, unless a nice comment says that it is a c++ header only file.
And IMHO renaming the file to .hpp is much more clearer than writing any comment.

If a file is used by a library and we can't therefore just rename it, without clients having to adapt their code, it is always possible to rename it, and provide a "deprecated" .h file that includes the .hpp file.
There are probably other possibilities for dealing with it.

It is also possible to update the file name convention every time a file is updated.
Yes, it will lead in the short term to an inconsistent code base, but not necessarily in a more chaotic situation.
But if you think about it, every time a new guideline, bets practice or improvement is applied to a codebase, in the short term it will be less consistent than before.

To conclude:

If we really do not want to tell people how to name their files (as Bjarne already stated in this discussion), then we should also not tell them to name it with a .h file extension.
If there is really no consensus, the best thing (IMHO) would be to list viable alternatives with advantages and disadvantages.

Therefore I would like to propose to update the guideline in something like:

A convention used by many popular projects is to use `.h` as file ending.
By using a different file ending between C and C++ files (the most used are `.hpp` and `.hh`), there are certain advantages

 - distinction between c and c++ files
 - tooling can get better results/less false positives
 - ...

It is important to be consistent..., but it is also possible to ...

@jwakely
Copy link
Contributor

jwakely commented Mar 14, 2018

N.B. that should say "C and C++" not "c and c++", and "fewer" not "less".

Renaming files can make it harder to follow history in version control, and so can cause problems of its own.

As with all guidelines in the NL section, if you have a different preference or follow a different convention, ignore the guideline. The intro to that section is clear about that.

@bdeeming
Copy link

Just because a guideline can be ignored by an individual, does not mean that there is no room to improve it.
I would like to re-emphasize that the recommendation from @fekir and @GiovanniDicanio et al., is that there are some valuable additions to the rule that can be made to point out the advantages of '.hpp'/'.hh', thus improving it, not overwriting it. And those additions do not contradict the existing advice, they instead complement it by adding additional context to the reasoning - a balanced argument, which in turn makes it easier for someone to confidently use (or ignore) the guideline.
If we focus on the intended user of this guideline, then they will be someone likely asking "Given I'm starting a new project, what should I name my headers with?". They will read this guideline, and depending on their personality/project requirements will be able to evaluate which extension will give them the most benefit. For example, if they're someone who likes the 'safe' tried-n-true, then they would pick '.h'. If they're someone who sees value in having their linter automatically detect the file as C++, then they will pick '.hpp'/'.hh'. But they will do so informed of the main trade-offs that they'll be making - a good outcome.
In this way the guideline is both advancing the state-of-the-art (the ultimate goal of the guidelines), but not declining the currently wide-spread status quo that 'works' (to make the guidelines real-world usable, in full, in existing C++ projects).

@blakehawkins
Copy link
Member

blakehawkins commented Mar 14, 2018

A convention used by many popular projects is to use .h as file ending.

I consider this statement at best, correct, but at worst, harmful. I think: if it feels wrong to add a note about hpp/hxx/hh, then it feels even more wrong to add a note about using .h.

E: Also FWIW I don't think this is bike-shedding. Lots of tools like cpplint don't use a full-blown c++ parser, so using file extensions as a way to categorise code can be powerful and cheap. I consider this issue to be pretty important, and interesting.

@johnthagen
Copy link

Lots of tools like cpplint don't use a full-blown c++ parser

FWIW, I've run into this exact problem when developing a Cppcheck plugin for CLion. Each file is analyzed independently and when looking at a .h file, I don't have the context to know whether to set Cppcheck to use C or C++.

The concerns others have raised about code churn and status quo are legitimate, though.

@MikeGitb
Copy link

MikeGitb commented Mar 14, 2018

I also think, .hpp and it's advantages should at least be mentioned (and Ideally even recommended).

There is nothing wrong in recognizing and allowing established practice, but that shouldn't stop guidelines from recommending better alternatives for situations, where consistency is not an issue.

Most counterarguments seem to be: "We don't want to force users to make big changes unless there is a big benefit to it". Well, no one is suggesting a mandatory core-guideline-checker that will complain on every .h file. It wasn't even suggested to drop the .h recommendation (although I'd prefer that) and just like the formatting guidelines (and many other guidelines) it will be ignored by any project with established conventions anyway.

However, for new or small projects, using a distinct extension for c++ headers comes at pretty much zero cost and has the advantage of clearly documenting intent to both tools (no need for magic strings in the file) and other users.

From the possible alternatives (.cpp/.h, .cpp/.hpp, .cc/.hh, .cxx/.hxx) I find hpp most convicing. Simply because it mirrors cpp and it is the only alternative to .h that I've seen in common libraries such as boost. But that is of course only speaking from (limited) personal experience.

As a final thought: Even if you don't want to change the recommendation, personally, I would shrink the whole section down to


SF.1: Use a .cpp suffix for code files and .h for interface files if your project doesn't already follow another convention

Reason
It's a longstanding convention. But consistency is more important, so if your project uses something else, follow that.

Note
The specific names .h and .cpp are not required (just recommended as a default) and other names like .cpp/.hpp, .cc/.hh, .cxx/.hxx are in widespread use (see #686 for more discussions on that topic). Use such names equivalently. In this document, we refer to .h and .cpp as a shorthand for header and implementation files, even though the actual extension may be different.

Enforcement

  • Flag non-conventional file names.
  • Check that .h and .cpp (and equivalents) follow the rules below.

Anything else is either unrelated (like the examples) or distracts from the main reason of following existing practice (like the note about c-headers being used in c++ projects) and leads to more bikeshedding. Sometimes less is more.

ericwomer pushed a commit to ericwomer/raytracer that referenced this issue Oct 27, 2018
…es, also removed the PP from the end of the inclusion guards where applicable.

Renamed header extensions back to .h from .hpp as suggested by Bjarne Stroustrup when suggested to add header file extensions as .hpp as a standard isocpp/CppCoreGuidelines#686 (comment)
Changed all #include statements to point to the newly renamed headers.
Got it back up to the compile status before the rabbit hole.
ericwomer added a commit to ericwomer/skeleton that referenced this issue Dec 26, 2019
…es, also removed the PP from the end of the inclusion guards where applicable.

Renamed header extensions back to .h from .hpp as suggested by Bjarne Stroustrup when suggested to add header file extensions as .hpp as a standard isocpp/CppCoreGuidelines#686 (comment)
Changed all #include statements to point to the newly renamed headers.
Got it back up to the compile status before the rabbit hole.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests