I'm creating a presentation on modules, and I was looking for some punchy descriptions of it. Something like, I dunno, "Compiler-managed dependencies" or "The death of header files" or something like that. What would you guys suggest?
I am yet to see any real description about C++ modules, and thus it is unclear what the feature is exactly about. It was maybe Herb who told in one of his talks that Modules mean different things to different people. Sure, "The death of header files" sounds good, but is it really about that? (I'd even say if it is, then it does not worth the trouble at all - go get a real IDE instead.)
Would you mind explaining what features would a "real IDE" have that mitigate the pains of header files?
What are those "pains" header files cause?
A bigger benefit I see in Modules that it gives some kind of DLL-ish/.so-ish concept, what is missing from the standard since.. forever, but that has absolutely nothing to do with header files, so my question still stands..
On Thu, Jul 11, 2013 at 9:55 PM, Róbert Dávid <lrd...@gmail.com> wrote:
A bigger benefit I see in Modules that it gives some kind of DLL-ish/.so-ish concept, what is missing from the standard since.. forever, but that has absolutely nothing to do with header files, so my question still stands..
No Modules apparently are not about defining library linking.
No, the current system as defined does not care about how the
filesystem is structured. The fact that all the implementations we
have are based on that premise is not due to the standard. The
standard leaves the "where to find the headers" bit completely
implementation-defined. Blame the implementations for sticking to the
traditional model all these years.
Modules, or anything in the standard, including TRs/TS', does not define shared libraries, it just defines something, that is quite close to a library. The same way there is zero standard text about header files and .cpp files, just includes and compilation units. You are free to represent them in any way: it is equally conforming implementation to read up all compilation units and include headers from an SQL database, a web server, whatever, it just "happen to be" that all implementations are file-based. It also does not tell you how to represent results of compilation and linking.
2013. július 9., kedd 16:20:06 UTC+2 időpontban Klaim - Joël Lamotte a következőt írta:On Tue, Jul 9, 2013 at 1:17 AM, Róbert Dávid <lrd...@gmail.com> wrote:
What are those "pains" header files cause?
Did you read the rationale from the Modules paper?If not you should.Joel Lamotte
Well I did, but all I see there is 'faster compilation', any other benefit explained is foggy.
On Thursday, July 11, 2013 12:55:48 PM UTC-7, Róbert Dávid wrote:
2013. július 9., kedd 16:20:06 UTC+2 időpontban Klaim - Joël Lamotte a következőt írta:On Tue, Jul 9, 2013 at 1:17 AM, Róbert Dávid <lrd...@gmail.com> wrote:
What are those "pains" header files cause?
Did you read the rationale from the Modules paper?If not you should.Joel Lamotte
Well I did, but all I see there is 'faster compilation', any other benefit explained is foggy.
That's because there is no other reason for modules. The original proposal for modules talks about DLLs and such, but the primary focus of the current modules definition and implementation (which admittedly is not a formal proposal yet; it's being built as an implementation first, with guidance by the committee, in order to prove that it can actually work and does what it is expected to. Thus avoiding the `export` issue) is to massively reduce compile times.
Modules are basically automatically generated, fine-grained precompiled headers. That's their purpose.
The fundamental problem with C++'s compilation module is that every .cpp file must compile ever header. Every time. Every time you #include <vector>, the compiler must include all of that code and compile it. Even though the compilation results will be exactly the same every time, it still has to do it. If you make one change to a .cpp file, the compiler still has to recompile <vector>.
If you change <vector>, then every .cpp file that includes it must be recompiled. And remember: recompiling a .cpp means recompiling every header that .cpp includes, directly or incorrectly. So if you change <vector>, and a .cpp file includes <iostream>, you have to recompile that .cpp's include of <iostream> too.
The idea with the current incarnation of modules is that you can use headers, but the system will substitute #includes for import directives. When it first includes a module header file, it will build a symbol definition file for that header. All other subsequent includes will just read the symbol definitions, which are pre-compiled source code, not live C++.
In this way, modules replicate the functionality of headers as much as possible. Included among the symbols for a module are macros too; it was deemed vital to allow macros to be part of modules, and for one module to rely on macros defined by another.
The current version of modules isn't necessarily about getting rid of headers (though you can do that too). The system is designed to allow you to use headers as normal and get the compilation benefits of modules via the use of an external module map file.
Ah come on, <vector> is part of the C++ implementation, just like the compiler or the linker. Does it come as a surprise to anyone that I need to recompile when I change the compiler, unless it is ABI-compatible? Is it a surprise to anyone that I need to recompile when I change the standard headers to an ABI-incompatible one? How does modules prevent the necessity of recompiling stuff for a changed vector module?
Precompiling headers on first include (with the same feature set) seems like something that any current implementation could do, we don't need a standard extension for that..
So far, Modules is just "let's make the include problem more complex with throwing import in the picture, and force implementers into one given kind of performance optimization"?
This sounds quite alarming to me. There should be more to it, I know how smart people are working on it. Does Modules allow something that I could not do without?
2013. július 15., hétfő 4:19:56 UTC+2 időpontban Nicol Bolas a következőt írta:
On Thursday, July 11, 2013 12:55:48 PM UTC-7, Róbert Dávid wrote:
2013. július 9., kedd 16:20:06 UTC+2 időpontban Klaim - Joël Lamotte a következőt írta:On Tue, Jul 9, 2013 at 1:17 AM, Róbert Dávid <lrd...@gmail.com> wrote:
What are those "pains" header files cause?
Did you read the rationale from the Modules paper?If not you should.Joel Lamotte
Well I did, but all I see there is 'faster compilation', any other benefit explained is foggy.
That's because there is no other reason for modules. The original proposal for modules talks about DLLs and such, but the primary focus of the current modules definition and implementation (which admittedly is not a formal proposal yet; it's being built as an implementation first, with guidance by the committee, in order to prove that it can actually work and does what it is expected to. Thus avoiding the `export` issue) is to massively reduce compile times.
Modules are basically automatically generated, fine-grained precompiled headers. That's their purpose.
The fundamental problem with C++'s compilation module is that every .cpp file must compile ever header. Every time. Every time you #include <vector>, the compiler must include all of that code and compile it. Even though the compilation results will be exactly the same every time, it still has to do it. If you make one change to a .cpp file, the compiler still has to recompile <vector>.
If you change <vector>, then every .cpp file that includes it must be recompiled. And remember: recompiling a .cpp means recompiling every header that .cpp includes, directly or incorrectly. So if you change <vector>, and a .cpp file includes <iostream>, you have to recompile that .cpp's include of <iostream> too.Ah come on, <vector> is part of the C++ implementation, just like the compiler or the linker. Does it come as a surprise to anyone that I need to recompile when I change the compiler, unless it is ABI-compatible? Is it a surprise to anyone that I need to recompile when I change the standard headers to an ABI-incompatible one? How does modules prevent the necessity of recompiling stuff for a changed vector module?
#include <vector>
#include <iostream>
int main()
{
std::vector<float> v{5.0, 4.3};
for(auto &i : v)
std::cout << i << std::endl;
}
The idea with the current incarnation of modules is that you can use headers, but the system will substitute #includes for import directives. When it first includes a module header file, it will build a symbol definition file for that header. All other subsequent includes will just read the symbol definitions, which are pre-compiled source code, not live C++.Precompiling headers on first include (with the same feature set) seems like something that any current implementation could do, we don't need a standard extension for that.
But I think that is not the acutal solution to the problem you described: we need to recompile dependencies when the interface provided by the header is changes, something that MSVC does with the "managed incremental build" feature (it's a different question how successfully).
In this way, modules replicate the functionality of headers as much as possible. Included among the symbols for a module are macros too; it was deemed vital to allow macros to be part of modules, and for one module to rely on macros defined by another.
The current version of modules isn't necessarily about getting rid of headers (though you can do that too). The system is designed to allow you to use headers as normal and get the compilation benefits of modules via the use of an external module map file.
So far, Modules is just "let's make the include problem more complex with throwing import in the picture, and force implementers into one given kind of performance optimization"?
This sounds quite alarming to me. There should be more to it, I know how smart people are working on it. Does Modules allow something that I could not do without?
Regards, Robert
`<vector>` and `<iostream>` may be "part of the C++ implementation," but they are still header files, and thus will be treated no differently than any other #inclusion in your code. If it helps you understand the issue, don't think of them as system files. You can mentally replace `<vector>` and `<iostream>` with `"myVector" and "myIosystem" and chance the classes accordingly. It changes nothing about how the compiler goes about handling them.
If you change `<vector>`, you must recompile all 200,000 lines of code, even though the 72,000 lines belonging to <iostream> have absolutely no dependencies on `<vector>` at all. The compiled result of `<iostream>` is completely unchanged. So why spend that time compiling 72,000 lines, when you only need to compile 138,000 + 10? Again, if these being standard library headers bothers you, you can think of them as just some large, template code headers that are part of your project.
The idea with the current incarnation of modules is that you can use headers, but the system will substitute #includes for import directives. When it first includes a module header file, it will build a symbol definition file for that header. All other subsequent includes will just read the symbol definitions, which are pre-compiled source code, not live C++.
#include works by copying text. The C++ standard requires that it works by copying text. And therefore, all of the definitions included by one #include must be visible to any subsequent code. Not just code written in the .cpp file doing the including, but also in code included after it.
Currently, if you #include a file, everyone who #includes you will gain access to that stuff whether they want to or not. We have come up with idioms to avoid exposing these internal details in header-only libraries, like using a `detail` namespace or whatever. But those details are still exposed; we just tell people to ignore them.
With modules you can explicitly state that some things you #include are internal to your module and are not to be exposed to those who include you. Bits of them can be exposed of course (private members of classes the user can use may have to be exposed). But the user can't name them directly, though type deduction could name them anyway.
That's not entirely correct. The standard requires that it behaves like if it would copy text. You can do any trick you want, if it is transparent. If you can detect that nothing has changed from line x to line y (including macros that could mess up the code), you can just pick up the result from the previous compilation. Implementations don't do that (except for the mentioned Managed Incremental Build) because it is hard, I guess Modules will help this a lot.
But that's not really possible in the general case. #including the same file from multiple translation units is not required to provide definitions that are ODR-equivalent definitions of the same symbol.