9 ms·
#include <rules> (2010)
- Hendrikto 3y agoSo many things to remember and potentially screw up. I am glad that modern languages come with fewer footguns.
- geertj 3y agoThe article is from 2010. C++20 solved the include file issue with modules. The ecosystem is almost there with CMake 3.28 (released) and GCC 14 (some time in H1 this year) providing out of the box support. For most practical purposes, modern c++ should be seen as a modern language. You need to make some effort to understand what language features not to use, but in my experience that effort is not too bad in the context of the overall development process. There are also some initiatives (cppfront is my favorite) to create an updated syntax where certain unsafe historic behaviors are not allowed.
- freedomben 3y agoIt surprises and saddens me how dismissed C++ is nowadays. It's rarely my first choice (unless writing a gui, then Qt is my go-to), but it is a far more modern and less dangerous language than most people think. With most technology, people don't assume it hasn't changed since the 90s, but for some reason, that's what people do with C++
- StopTheTechies 3y ago> but it is a far more modern and less dangerous language than most people think. I suspect a better answer here is that people have wildly different tolerances for safety and don't discuss the subjective aspects of interactions with programming languages.
- dns_snek 3y agoI've never written C++ in professional capacity, what turns me off from learning is what I've heard and read about its vast complexity, e.g. you could meet 20 expert C++ developers and they'd all be using a different subset of the language. I don't want to spend more energy learning a language than I do actually solving the problem. Same reasoning turns me off from Rust, too.
- bun_terminator 3y agoAs a pure c++ dev, this is true and a good reason. The committee is borderline sabotaging the language. On top of the anti-cpp crows slinging hitpieces
- ryandrake 3y agoModern C++ is great and I would choose it today if I were starting a project from scratch. I think people’s problem with C++ is the existing projects/code. If I were to join a random company today working with a C++ code base, it is very likely I’d be dealing with legacy code complete with all the 1990s footguns C++ dismissers dismiss. That code base would also likely have problems like requiring Visual C++ 6.0 to compile, emitting thousands of warnings that have been ignored for decades, and the company shipping the DEBUG executable because nobody can figure out how to get the RELEASE build to not crash. Often existing C++ projects come with 1990s era problems, so detractors can still legitimately use 30 year old arguments.
- JonChesterfield 3y agoModern C++ is mostly syntactic sugar over older C++. If you manage to walk the happy path entirely within said syntax the code looks quite pretty. Lots of the language design is about having a nicer way to express common ideas. If you stray from the happy path, the demons come for you. Or if your use case isn't met by the existing sugar. Or if you have a dependency which was written a couple of years ago that you need to reach into. And naturally the project started from scratch today, only using the very nicest C++ features, will be legacy code written wrong in three or six years from now as the language moves on. I wouldn't want to start a new project in C++ today but I'm not totally confident there's a better choice available.
- Xeamek 3y ago>more modern and less dangerous language than most people think Compared to what? Itself from 20 years ago? That's great, but not nearly enough. Cpp just has SO MUCH FRICTION that it's simply not worth it to deal with it. Maybe if you have 20yrs of cpp experience and carved out a specific way for yourself to avoid all of it while still being productive... But that's not really an argument. And sure, there are still some cases when the alternatives aren't ideal either (ie. Rust also having friction, especially in domain like games, or higher level languages being too slow). But cpp has so much downsides I don't see why should one ever default into choosing cpp, unless you REALLY care about the benefits it brings. But those upsides are usually external (ie. ecosystem), rather then features of the language itself https://bitbashing.io/std-visit.html https://bitbashing.io/std-visit.html
- marcosdumay 3y ago> and carved out a specific way for yourself to avoid all of it while still being productive I believe such person exists when I see one. All that I see around are people claiming they did that, while ignoring some huge issue with their style that inserts some really nasty bugs on their software. Instead, the only C++ code that works out there is created by committee and peer-reviewed, so that different styles compensate each other.
- geertj 3y ago> I believe such person exists when I see one. All that I see around are people claiming they did that, while ignoring some huge issue with their style that inserts some really nasty bugs on their software. The real question is, of 100 bugs in a real-world application, how many were caused or at least influenced by the language, and how many are application level errors. In my practical experience bugs due to C++ behavior have just not been a thing. Maybe your world is different.
- tsimionescu 3y ago> it is a far more modern and less dangerous language than most people think. I think the opposite tends to be true. C++ is a more dangerous language than most people think, and many who see some nice new constructs end up with a false sense of security. In any major C++ project you will sooner rather than later find pieces that don't strictly respect all of the rules of modern C++, that end up accidentally invoking UB, and that will happily pass code review and de testing before blowing up when something else changes. People tend to believe they can write safe C++, but outside constrained environments (similar to MISRA C) , this has not been proven true in practice.
- lmm 3y ago> With most technology, people don't assume it hasn't changed since the 90s, but for some reason, that's what people do with C++ Disagree, every technology is like this. Talk to people about Maven and they think the 2005-era reasons not to use it are valid. Mention MongoDB and people think it's 2015. The industry is seemingly only ever willing to progress by adopting new things, not by fixing existing things.
- lmz 3y ago> C++20 solved the include file issue with modules. The ecosystem is almost there with CMake 3.28 (released) and GCC 14 (some time in H1 this year) providing out of the box support. So it's not widely supported yet in the newest released versions of the compiler and the article probably is still good advice until your project knows it no longer needs to compule using older versions?
- IAmLiterallyAB 3y ago> GCC 14 Do you have a reference for significant module changes in GCC 14? I see nothing on the changes page for 14
- geertj 3y agohttps://cmake.org/cmake/help/latest/manual/cmake-cxxmodules.7.html https://cmake.org/cmake/help/latest/manual/cmake-cxxmodules....
- loeg 3y agoC++20 may provide a theoretical solution but we're a long way from "it is practical and everyone easily replaces their headers with modules." In 2024 I am still manually writing C++ headers for my Fortune 100 employer.
- tsimionescu 3y ago> C++20 solved the include file issue with modules. The ecosystem is almost there with CMake 3.28 (released) and GCC 14 (some time in H1 this year) providing out of the box support. According to CPPReference [0], there isn't a single compiler release available today that fully supports C++20 modules. So perhaps "it's fixed" is a bit early. Especially since C++ projects tend to lag the latest release of their compiler by a few years, so even if GCC14 will indeed be the first C++ compiler to support modules fully, you still need to learn to use include guards today if you're going to be working in C++. This is one of the major problems of "modern C++" by the way. Major features always exist in principle long before they actually exist in practice (concepts being the other feature that took years to fully be supported). [0] https://en.cppreference.com/w/cpp/compiler_support https://en.cppreference.com/w/cpp/compiler_support
- dataflow 3y ago> According to CPPReference [0], there isn't a single compiler release available today that fully supports C++20 modules Seems to me like MSVC does at least? What do you see it missing?
- tsimionescu 3y agoI don't know the details, but the table is saying "partial" for MSVC as well, right? Edit: at a deeper look, I think I misread the table a bit, I guess it's saying that the feature is partially supported in MSVC 19.00 and 19.10, but full support in 19.28. Sorry about that misunderstanding.
- JonChesterfield 3y agoGood stuff, if slightly self-contradictory in places. The header file named after the source should be included first (to catch errors in the header) and the header file defining various macros should be included first (as otherwise it doesn't work). The detect-missing-includes-in-header is better handled by a separate compilation job which compiles the header by itself as it if was C++, `clang -xc foo.h`, solely for the purpose of catching that error. Then the include your own header first rule no longer matters. Forward declarations have a cost which the article misses. When the thing in question changes, your compiler no longer warns you when the forward declaration is out of sync with the real thing, and the linker diagnostics are usually less comprehensible. Also it's a nuisance to update all the forward declarations. An <iosfwd> style header, included at the top of the <ios> header, gives ~99% of the compile time advantage of forward declarations with none of the failure modes and usually less typing in the caller.
- mike_hock 3y agoIt basically consists of: 1) The basic, ubiquitous, and uncontroversial rule that headers should be self-contained, i.e. guarded and include their direct dependencies, and 2) nonsensical rules resulting from failure to follow the first rule, or failure to follow the other basic, ubiquitous and uncontroversial rule that source files should also include their direct dependencies. Manual forward declarations are a non-starter. Any header that contains a class declaration that it might ever make sense to refer to as an incomplete type (so, like, 100% of all classes, rounded to 3 decimal places) should have a corresponding iosfwd-style forward header. The common header is just another header. You include it if you need it and you don't if you don't.
- SAI_Peregrinus 3y agoExactly. If the order of your includes matters, you screwed up. Run "Include What You Use", fix the errors.
- mort96 3y agoThere's nothing self-contradictory. The two rules you're speaking of are: make sure that your header file is the first #include in the corresponding source file, except the common header, if your codebase has one. and: make sure that each source file includes the common header before everything else This defines a pretty clear order: 1) common header, if it exists; 2) the corresponding header for the source file, if it exists; 3) other headers needed by the source file.
- hielke 3y agoIn modern C++ there will be modules (C++20). Even std will be available as a module (C++23). This will likely bring down compile times massively. But so far the only compiler with support for this today is MSVC.
- JonChesterfield 3y agoDid someone get around the modules-linearise-the-build-graph problem? In the before times, people were enraged with C++ compile times and wanted a solution. Modules could have fixed that, thus people assumed modules would fix that. Then modules were designed with the primary motive of removing preprocessor macros from the language, with reference to fortran's binary module description model. The one that turns the trivially parallel compilation model into a directed graph. I'm under the impression that C++ modules as shipped require you to build dependencies before uses and the inevitable linearisation of the build graph is considered "probably fine, whatever". Compiling individual translation units gets somewhat faster as you don't need to parse the headers each time, but you can no longer build everything simultaneously. Do modules actually make compilation appreciably faster in msvc?
- synergy20 3y agoare you saying with c++ module parallel make is nearly impossible?
- NekkoDroid 3y agoits not impossible compiling independent modules parallel, but if module X depends on module Y, module Y needs to be compiled before module X.
- JonChesterfield 3y agoWith headers, every translation unit is some (probably large) amount of text spliced together then fed into the compiler front end. You parse <vector> and <string> over and over again. If headers are big or templates many, the time per translation unit get rather high. With modules, as of the last time I looked, in order to compile some file, you must first compile the files it depends on, at least far enough to create a module file which is then depended on. Compiling a single translation unit with a bunch of already-existing module files should be faster than the equivalent with a lot of header files as you don't need to repeat the parsing. This makes the individual compilations cheaper (win) but replaces independent work with a dependency graph traversal (loss). It's totally obvious from the outside that the right solution is a compiler daemon. Integrate the build system with the compiler, persist state between separate file compilations. The C/C++ world really likes the independent batch compiler scheduled by cmake approach though so that arbitrarily constrains their design space. It's fascinating that tooling choices from the early days (notably separate compilation is forced by insufficient memory) combined with the division of responsibility between compiler tooling vendors and the standards committee forces this sort of design.
- mgaunard 3y agothis is still lacking a lot of important rules (group by nature of dependency, sort alphabetically within a group, sort groups per dependency level, use angle brackets for third-party only) and is still only barely scratching the surface of C++ file organization.
- coldtea 3y ago>We’re stuck with C++, at least for another console generation. That was 14 years ago. C++ is not going anywhere, whether 1, 2, or 10 "console generations" ahead.
- 38 3y agoyeah, it is. the percentage of new C++ projects has plummeted, compared to modern options such as Rust or Go. developers are sick and tired of the awful tooling and decades old issues with C++, that will likely never be fixed. I for one will never touch a C++ code base again if I can avoid it.
- synergy20 3y agosource?
- IshKebab 3y agoThis is the best measure I've found: https://madnight.github.io/githut/#/pushes/2023/4 https://madnight.github.io/githut/#/pushes/2023/4 Unfortunately it doesn't have new projects, but it does seem like C++ peaked a couple of years ago and is starting to trend down. "Plummeting" is clearly an exaggeration though.
- cherryteastain 3y agoBased on the graphs here, Go and Python are also stagnant/slightly declining. Rust seems to be stagnant too since 2022.
- marcosdumay 3y agoThe best I can make from the graph is that those declines are a scaling adjustment for a recent meteoric Java growth. (WTF is there a meteoric Java growth is yet to be explained.)
- matheusmoreira 3y agoA great way to handle context-specific headers: common path rooted in context-specific directories coupled with include path management. Useful for platform- and architecture-specific code but can be used for anything really. Anything you want to parameterize and compile conditionally. Instead of this mess: #if APP_LINUX #include <app/linux.h> #elif APP_BSD #include <app/bsd.h> #elif APP_MACOS #include <app/macos.h> #else #error "Unsupported platform" #endif Organize things like this instead: linux/include/app/platform.h bsd/include/app/platform.h macos/include/app/platform.h Then in the makefile: # Detect it somehow # or have user provide it PLATFORM ?= $(shell uname -s) cc -I include -I $(PLATFORM)/include Then in the source code: #include <app/platform.h>
- actionfromafar 3y agoSomething similar in spirit but Meson is what I have settled on. It’s all trade offs all the way down, but it’s what works for me.
- JonChesterfield 3y agoMoving logic from the source code into the compiler invocation is a mixed blessing. In general as the list of -I directories needed to build the thing gets more complicated the ease of building it from something other than the provided build scripts goes down. Much like working things out in the preprocessor is ugly but works with other build systems and over-elaborate configure script style stuff makes for prettier source by moving complexity elsewhere.
- eps 3y agoAmen. That's the way.
- delta_p_delta_x 3y ago+1. I think platform-specific software architecture should be lifted into the build system rather than in the code. This is straightforward with CMake, Meson, Build2, etc. `#ifdef` is a very bad idea and tends to make for leaky abstractions. It litters the code with platform selection and platform-specific behaviour that should ideally be abstracted away, e.g. things like `CreateProcess` vs `fork(); exec();`. With C++20 named modules, this is made even easier, and there is no need to even have an `app/platform.h`. Programmers can literally copy-paste the function declarations into different files, and just select the correct module interface at configure time, and just write import app; Again, most new-ish build systems support this too.
- commandersaki 3y ago>Oh, did I mention that good header dependencies decrease the linking time? How?
- tlb 3y agoFunction definitions in headers are compiled and included in the object file, then all but one copy is discarded during linking. Reading and discarding all this stuff adds some time to the linking process, which is a noticeable fraction of total build time if you're only recompiling one source file.
- JonChesterfield 3y agoModerately interesting that the compile-N-times-keep-one is a C++ thing. C's inline makes you specify which translation unit exports the symbol so the compiler knows whether it is working with the canonical symbol or one that it can discard at will. Thus it can inline functions, but if it chooses not to, it doesn't have to optimise&codegen that function just to have the linker probably throw it away.
- kimixa 3y agoYou can do the same for c++ with extern templates, just instantiate them with the needed types in one compilation unit and you only end up with a single set of symbols, and codegen etc. only runs the once. And C inline functions are instantiated and generated for every compilation unit that uses it - it just doesn't generate exported symbols in the resulting object file. Exactly the same as the "inline" keyword in c++.
- astrobe_ 3y agoDeclarations, not definitions. Declarations go into object files as symbol names for the purpose of linking. You can have multiple declarations as long as they are the same (or if they are not they define different things in C++ due to overloading), but you cannot have multiple definitions (even in different object files) even if they are identical (compiler doesn't bother checking they are, it sees it as fishy and just drops a "multiple definitions" error).
- rogual 3y agoI no longer use header files when I can help it. They haven't made sense since 1980. I have a Python script that reads my C++ source and writes all the headers for me. C++ is so much nicer to write when you don't have to do the compiler's job for it. Modules are supposed to be coming soon, and then I won't even need the script anymore.
- casey2 3y agoJust don't put include files inside other include files.