Hacker News new | ask | show | jobs
by yunnpp 141 days ago
I recently started a pet project using modules in MSVC, the compiler that at present has best support for modules, and ran into a compiler bug where it didn't know how to compile and asked me to "change the code around this line".

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.

5 comments

I still hope that modules become mature and safe for production code. Initially I coded in C/C++ and this header #include/#ifndef approach seemed OK at that time. But after using other programming languages, this approach started to feel too boilerplate and archaic. No sane programming language should require a duplication in order to export something (for example, the full function and its prototype), you should write something once and easily export.
I think everyone hopes/hoped for a sane and useful version of modules, one that would provide substantial improvements to compilation speed and make things like packaging libraries and dealing with dependencies a lot more sane.

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.

> It's an incredibly convoluted mess that requires an enormous amount of effort for little benefit.

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.

> No sane programming language should require a duplication in order to export something (for example, the full function and its prototype)

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.

> Lots of closed source commercial libraries provide some .h files and a .so file.

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.

> 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.

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 ...

In most situations, auto-generating the equivalent of .h files for a library based on export statements in the source code would be fine and a useful simplification.
The .h could have been a compiler output, like the .so
Not for things like public/private, static, virtual. Not for inheritance, either.
You add all those things in a single .c or .cpp source, without manual authoring of .h files (this may require language changes, maybe in C30 and C++30 or something)

Then whatever is relevant to the public interface gets generated by the compiler and put in a .h file. This file is not put in the same directory of the .c file to not encourage people to put the .h file in version control.

The C language is too complicated and too flexible to allow that. If you are starting from scratch and creating a new language, this could be a design goal from the beginning.
> The C language is too complicated and too flexible to allow that.

I disagree. In fact, I would expect the following could be a pretty reasonable exercise in a book like "Software Tools"[1]: "Write a program to extract all the function declarations from a C header file that does not contain any macro-preprocessor directives." This requires writing a full C lexer; a parser for function declarations (but for function and struct bodies you can do simple brace-matching); and nothing else. To make this tool useful in production, you must either write a full C preprocessor, or else use a pipeline to compose your tool with `cpp` or `gcc -E`. Which is the better choice?

However, I do see that the actual "Software Tools" book doesn't get as advanced as lexing/parsing; it goes only as far as the tools we today call `grep` and `sed`.

I certainly agree that doing the same for C++ would require a full-blown compiler, because of context-dependent constructs like `decltype(arbitrary-expression)::x < y > (z)`; but there's nothing like that in K&R-era C, or even in C89.

No, I think the only reason such a declaration-extracting tool wasn't disseminated widely at the time (say, the mid-to-late 1970s) is that the cost-benefit ratio wouldn't have been seen as very rewarding. It would automate only half the task of writing a header file: the other and more difficult half is writing the accompanying code comments, which cannot be automated. Also, programmers of that era might be more likely to start with the header file (the interface and documentation), and proceed to the implementation only afterward.

[1] - K&P's "Software Tools" was originally published in 1976, with exercises in Ratfor. "Software Tools in Pascal" (1981) is here: https://archive.org/details/softwaretoolsinp00kern/

> Write a program to extract all the function declarations from a C header file that does not contain any macro-preprocessor directives

There you go. You just threw away the most difficult part of the problem: the macros. Even a medium-sized C library can have maybe 500 lines of dense macros with ifdef/endif/define which depends on the platform, the CPU architecture, as well as user-configurable options at ./configure time. Should you evaluate the macro ifdefs or preserve them when you extract the header? It depends on each macro!

And your tool would still be highly incomplete because it only handles function declarations not struct definitions, typedefs you expect the users to use.

> the other and more difficult half is writing the accompanying code comments, which cannot be automated

Again disagree. Newer languages have taught us that it is valuable to have two syntaxes for comments, one intended for implementation and one intended for the interface. It’s more popularly known as docstrings but you can just reuse the comment syntax and differentiate between // and /// comments for example. The hypothetical extractor tool will work no differently from a documentation extractor tool.

Modules are still in the early adoptor phase - despite 3 years. there are unfortunately bugs, and we still need people to write the "best practices for C++ modules" books. Everyone who has use them overall says they are good things and worth learning, but there is a lot about using them well that we haven't figured out.
Best practice for C++ modules: avoid.

(Buy my book)

Modules have been working reasonably well in clang for a while now but MSVC support is indeed buggy.
They are using modules in the MS Office team:

https://devblogs.microsoft.com/cppblog/integrating-c-header-...

This is untrue. The MS Office team is using a non-standard MSVC compiler flag that turns standard #include into header units, which treats those header files in a way similar to precompiled header files. This requires no changes to source code, except for some corner cases they mention in that very blog post to work around some compiler quirks.

That is not the same as using modules, which they have not done.

There's nothing non-standard happening there. The compiler is allowed to translate #include -> import. Here's the standardese expressing that: https://eel.is/c%2B%2Bdraft/cpp.include#10.

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!

I'm afraid things will continue very much sucking for a long time and will still be less-than even when they become broadly supported since sepples programmers, being real programmers™, are not entitled to have nice things.