C++ Modules Are Here to Stay
Posted by faresahmed 5 days ago
Comments
Comment by yunnpp 5 hours ago
So no, modules aren't even here, let alone to stay.
Never mind using modules in an actual project when I could repro a bug so easily. The people preaching modules must not be using them seriously, or otherwise I simply do not understand what weed they are smoking. I would very much appreciate to stand corrected, however.
Comment by senfiaj 4 hours ago
Comment by Maxatar 3 hours ago
The version of modules that got standardized is anything but that. It's an incredibly convoluted mess that requires an enormous amount of effort for little benefit.
Comment by senfiaj 2 hours ago
I'd say C++ as a whole is a complete mess. While it's powerful (including OOP), it's complicated and inconsistent language with a lot of historical baggage (40+ years). That's why people and companies still search for (or even already use) viable replacements for C++, such as Rust, Zig, etc.
Comment by kccqzy 3 hours ago
You are spoiled by the explosive growth of open source and the ease of accessing source code. Lots of closed source commercial libraries provide some .h files and a .so file. And even when open source, when you install a library from a package from a distribution or just a tarball, it usually installs some .h files and a .so file.
The separation between interface and implementation into separate files was a good idea. The idea seemed to be going out of vogue but it’s still a good idea.
Comment by senfiaj 3 hours ago
I'm mostly talking about modules for internal implementation, which is likely to be the bulk of the exports. Yes, it's understandable that for dll / so files exporting something for external executables is more complicated also because of ABI compatibility concerns (we use things like extern "C"). So, yes header approach might be justified in this case, but as I stated, such exports are probably a fraction of all exports (if they are needed at all). I'll still prefer modules when it's possible to avoid them.
Comment by AgentME 3 hours ago
Comment by johannes1234321 2 hours ago
However as soon as you do C++ that goes away. With C++ you need implementation of templates available to the consumer (except cases with limited set of types where you can extern them), wmin many cases you get many small functions (basic operator implementations, begin()/end() for iterators in all variations etc.) which benefit from inking, thus need to be in the header.
Oh and did I mention class declarations tonthe the class size ... or more generic and even with plain C: As soon as the client should know about the size of a type (for being able to allocate it, have an array of those etc) you can't provide the size by itself, but you have to provide the full type declaration with all types down the rabbit hole. Till you somewhere introduce a pointer to opaque type indirection.
And then there macros ...
Modules attempt to do that better, by providing just the interface in a file. But hey, C++ standard doesn't "know" about those, so module interface files aren't a portable thing ...
Comment by bluGill 3 hours ago
Comment by alextingle 3 hours ago
(Buy my book)
Comment by malfmalf 3 hours ago
https://devblogs.microsoft.com/cppblog/integrating-c-header-...
Comment by Maxatar 3 hours ago
That is not the same as using modules, which they have not done.
Comment by starfreakclone 54 minutes ago
I do agree, it's not _exactly_ the same as using _named modules_, but header units share an almost identical piece of machinery in the compiler as named modules. This makes the (future planned) transition to named modules a lot easier since we know the underlying machinery works.
The actual blocker for named modules is not MSVC, it's other compilers catching up--which clang and gcc are doing quite quickly!
Comment by vitaut 3 hours ago
Comment by throw_sepples 1 hour ago
Comment by rienbdj 5 hours ago
Comment by 20k 3 hours ago
There literally isn't a plan or direction in place to add any way to compete with Rust in the safety space currently. They've got maybe until c++29 to standardise lifetimes, and then C++ will transition to a legacy language
Comment by direwolf20 1 hour ago
Comment by pornel 35 minutes ago
The C++ WG keeps looking down at C and the old C++ sins, sees their unsafety, and still thinks that's the problem to fix.
Rust looks the same way at modern C++. The std collections and smart pointers already existed before the Rust project has been started. Modern C++ is the safety failure that motivated creation of Rust.
Comment by reactjs_ 6 hours ago
Program
- Module
- Module Partition
whereas in module systems that support module visibility, like Rust’s, you can decompose your program at multiple abstraction levels: Program
- Private Module
- Private Module
- Private Module
- Public Module
- Public Module
Maybe I am missing something. It seems like you will have to rely on discipline and documentation to enforce clean code layering in C++.Comment by pdpi 5 hours ago
Comment by pjmlp 4 hours ago
Rust, Modula-2 and Ada are probably the only ones with module nesting.
Comment by groby_b 5 hours ago
"Just one more level bro, I swear. One more".
I fully expect to sooner or later see a retcon on why really, two is the right number.
Yeah, I'm salty about this. "Submodules encourage dependency messes" is just trying to fix substandard engineering across many teams via enforcement of somewhat arbitrary rules. That has never worked in the history of programming. "The determined Real Programmer can write FORTRAN programs in any language" is still true.
Comment by bluGill 3 hours ago
Comment by pornel 1 hour ago
Comment by groby_b 2 hours ago
And sure, "future extension" is nice. But not if the future arrives at an absolutely glacial pace and is technically more like the past.
This may be inevitable given the wide spread of the language, but it's also what's dooming the language to be the next COBOL. (On the upside, that means C++ folks can write themselves a yacht in retirement ;)
Comment by pklausler 2 hours ago
Comment by groby_b 1 hour ago
But, for the folks who didn't grow up with the Real Programmer jokes, this is rooted in a context of FORTRAN 77. Which was, uh, not famous for its readability or modularity. (But got stuff done, so there's that)
Comment by pklausler 42 minutes ago
Comment by w4rh4wk5 5 hours ago
Comment by srcreigh 5 hours ago
Log scale: Less than 3% done, but it looks like over 50%.
Estimated completion date: 10 March 2195
It would be less funny if they used an exponential model for the completion date to match the log scale.
Comment by w4rh4wk5 3 hours ago
Comment by mcdeltat 2 hours ago
Comment by w4rh4wk5 1 hour ago
Comment by ziml77 1 hour ago
Comment by fasterik 2 hours ago
- Single translation unit (main.cpp)
- Include all other cpp files in main
- Include files in dependency order (no forward declarations)
- No circular dependencies between files
- Each file has its own namespace (e.g. namespace draw in draw.cpp)
This works well for small to medium sized projects (on the order of 10k lines). I suspect it will scale to 100k-1M line projects as long as there is minimal use of features that kill compile times (e.g. templates).
Comment by zabzonk 2 hours ago
Comment by w4rh4wk5 1 hour ago
Comment by fooker 5 hours ago
The current solution chosen by compilers is to basically have a copy of your code for every dependency that wants to specialize something.
For template heavy code, this is a combinatorial explosion.
Comment by WalterBright 4 hours ago
Comment by amluto 3 hours ago
It’s regrettable that the question of whether a type meets the requirements to call some overload or to branch in a particular if constexpr expression, etc, can depend on what else is in scope.
Comment by direwolf20 1 hour ago
In Haskell, you can't ever check that a type doesn't implement a type class.
In Golang, a type can only implement an interface if the implementation is defined in the same module as the type.
In C++, in typical C++ style, it's the wild west and the compiler doesn't put guard rails on, and does what you would expect it to do if you think about how the compiler works, which probably isn't what you want.
I don't know what Rust does.
Comment by pornel 16 minutes ago
Generic code is stored in libraries as MIR, which is half way between AST and LLVM IR. It's still monomorphic and slow to optimize, but at least doesn't pay reparsing cost.
Comment by direwolf20 2 minutes ago
Comment by direwolf20 1 hour ago
Comment by fooker 1 hour ago
Comment by pjmlp 4 hours ago
Comment by fooker 4 hours ago
It does not work very well at all if your goal is to port your current large codebase to incrementally use modules to save on compile time and intermediate code size.
Comment by pjmlp 3 hours ago
Comment by jokoon 2 hours ago
I don't see many "fair" benchmarks about this, but I guess it is probably difficult to properly benchmarks module compilation as it can depend on cases.
If modules can reach that sort of speedup consistently, it's obviously great news.
Comment by cmovq 6 hours ago
Comment by nickelpro 5 hours ago
Chuanqi says "The data I have obtained from practice ranges from 25% to 45%, excluding the build time of third-party libraries, including the standard library."[1]
[1]: https://chuanqixu9.github.io/c++/2025/08/14/C++20-Modules.en...
Comment by luke5441 5 hours ago
Comment by direwolf20 1 hour ago
Comment by vitaut 3 hours ago
Comment by Night_Thastus 5 hours ago
Comment by feelamee 6 hours ago
Comment by nickelpro 5 hours ago
If these aren't compelling, there's no real reason.
Comment by WalterBright 4 hours ago
Comment by TimorousBestie 5 hours ago
It seems likely I’ll have to move away from C++, or perhaps more accurately it’s moving away from me.
Comment by bluGill 5 hours ago
Comment by jcranmer 4 hours ago
It kinda is. The C++ committee has been getting into a bad habit of dumping lots of not-entirely-working features into the standard and ignoring implementer feedback along the way. See https://wg21.link/p3962r0 for the incipient implementer revolt going on.
Comment by 20k 3 hours ago
So many features are starting to land which feel increasingly DoA, we seriously need a language fork
Comment by direwolf20 1 hour ago
Comment by amluto 3 hours ago
alignas(16) char buf[128];
What type is buf? What alignment does that type have? What alignment does buf have? Does the standard even say that alignof(buf) is a valid expression? The answers barely make sense.Given that this is the recommended replacement for aligned_storage, it’s kind of embarrassing that it works so poorly. My solution is to wrap it in a struct so that at least one aligned type is involved and so that static_assert can query it.
Comment by crote 4 hours ago
Just like Python was to blame for the horrible 2-to-3 switch, C++ is to blame for the poor handling of modules. They shouldn't have pushed through a significant backwards-incompatible change if the wide variety of vendor toolchains wasn't willing to adopt it.
Comment by krior 5 hours ago
Comment by juliangmp 5 hours ago
Comment by TimorousBestie 5 hours ago
Comment by Joker_vD 5 hours ago
How well does this usually work, by the way?
Comment by TimorousBestie 5 hours ago
Comment by direwolf20 1 hour ago
But you might not be able to use libraries that insist upon modules. There won't be many until modules are widespread.
Comment by maccard 4 hours ago
Comment by whobre 6 hours ago
Dude…
Comment by cocoto 3 hours ago
Comment by vitaut 3 hours ago
Comment by rovingeye 3 hours ago
Comment by direwolf20 1 hour ago
Comment by sethops1 3 hours ago
Comment by webdevver 4 hours ago
auto main(argc, argv) -> int
int argc;
char **argv;
to work, but alas it seems c++ threw pre-ansi argument type declarations out.Comment by zabzonk 3 hours ago
they never were in C++.
Comment by CamperBob2 6 hours ago
Comment by on_the_train 6 hours ago
Comment by Night_Thastus 5 hours ago
Comment by whobre 5 hours ago
Comment by cpburns2009 5 hours ago
> auto main() -> int
Isn't that declaring the return type twice, once as auto and the other as int?
Comment by yunnpp 5 hours ago
There is, however, a return type auto-deduction in recent standards iirc, which is especially useful for lambdas.
https://en.cppreference.com/w/cpp/language/auto.html
auto f() -> int; // OK: f returns int
auto g() { return 0.0; } // OK since C++14: g returns double
auto h(); // OK since C++14: h’s return type will be deduced when it is defined
Comment by maccard 4 hours ago
Comment by zabzonk 3 hours ago
Comment by few 5 hours ago
Comment by Davidbrcz 5 hours ago
Comment by direwolf20 1 hour ago
Comment by GrowingSideways 5 hours ago
Comment by up2isomorphism 4 hours ago
Comment by direwolf20 1 hour ago
Comment by GrowingSideways 5 hours ago