HelloNurse 2 days ago

If names must be unique, shouldn't there be a way to resolve conflicts by renaming the modules?

For example, if we use libraries A and B and both want to define module "foo", straightforward compiler options passed when compiling their sources could make the undisciplined libraries produce instead, in the context of our project, modules fooA and fooB and accordingly consume fooA or fooB (found in our project's module stash) where they reference their own module "foo", as if the replacement names had been used in export and import clauses.

Are module names completely erased from actually compiled libraries and executables? What complications am I missing?

  • masfuerte 2 days ago

    If names must be unique you don't need to rename them because they are unique.

    I'm not being facetious. It's a design choice. Many languages don't but Java and C# for example require modules to have globally unique fully qualified names.

    Maybe this was the intention of the C++ committee. C++ does support hierarchical module names so Java style naming is possible. If everyone adopts it then name clashes won't be a problem.

    • HelloNurse 2 days ago

      "Everyone" is an awful lot of people. In practice, there will be conflicts and there must be a good plan for handling them. Editing third party source code to change names is not a good plan.

      For example, without assuming wrong names on the part of third party developers, a project could compile multiple variants of the same library with the intent of segregating multiple copies of the same symbols (e.g. buried in other libraries as transitive dependencies, in different dynamic link libraries that are selected at runtime, in executable variants that are compiled collectively for convenience).

      This would be manageable with explicitly controlled object and library file names, but ambiguous if linking is funneled through ambiguously named modules.

      • masfuerte 2 days ago

        Global uniqueness works in Java. Modules are named with the organisation's DNS name in reverse (guaranteed unique) plus the module name or whatever additional structure you want. So Microsoft's evil module might be `com.microsoft.evil` or `com.microsoft.marketing.web.evil`.

        But as you say, this doesn't solve the problem of including multiple versions of the same module.

        • svieira 2 days ago

          > But as you say, this doesn't solve the problem of including multiple versions of the same module.

          The solution that Java has for that is literally re-writing the bytecode of version A to be "in a different module" and re-writing the bytecode of the code that depends on version A to use the "new" module. That's not going to fly for C++ as I understand it, but maybe I'm missing something.

          • HelloNurse a day ago

            Java bytecode files are not only portable and well designed but specifically organized with tables of names (so that the bytecode proper can concisely refer to names by index).

            The inconvenience of handling a binary format should be much smaller than the challenge of parsing C++ sources to find names.

usrnm 3 days ago

It doesn't really change much, name clashes are already an existing danger that can bite you at any moment you download somebody else's code from the Internet. Definitely not something unique to C++ modules and not an argument against them

  • 1718627440 2 days ago

    But the symbol names don't matter after linking. I can happily reuse a symbol name for something different after the previous symbol has been linked and does not appear anymore in the exported symbol table.

    • usrnm 2 days ago

      There are many, many ways to have a name conflict in C++. A lot of them don't even have anything to do with symbols or linking, like macro conflicts. And yes, they do happen, and they're not fun to debug.

      • ziml77 2 days ago

        Using a header file for kdb+ was great fun with its short macro and function names causing all sorts of weird breaks.

      • 1718627440 2 days ago

        Why do you put in foreign code (excluding declarations) in your translation unit? Isn't a translation unit under the control of a single party/vendor? And you can just undef them and the compiler gives a warning/error about the redefinition.

        • von_lohengramm 2 days ago

          That might be the case in C land, but C++ land usually has a lot more stuff in headers. For examples, templates are not very useful unless they're defined in headers.

          • pjmlp 2 days ago

            C has similar issues with macros and _Generic.

            C++ modules support having templates with private code, compilers than retrieve what they need from the BMI (Binary Module Interface), like in any other module based language that supports binary libraries.

            • 1718627440 2 days ago

              Yes, there can be problems. This can be counteracted by remembering that the file name does not make a header file. Having headers, i.e. forward declaration does make a C file a header file. They seams to be an aversion to include *.c files, but in my opinion doing the same in a *.h file makes the problem only worse.

              I think what is the right approach is to make sure, that a header file really only contains the "public" API. Common definitions or static/inline functions should be better put into a separate *.c file that is then included in multiple translation units, but since it is separate from the real API, it can be included in much less other files. Some also use the convention to name this files *.inc or *.imp .

              As for name conflicts, C has the tooling for this, as compilation and symbol handling are separate steps. It might not be the cleanest approach, but you can always bundle some translation units into a convenience library and apply a linker script, or strip symbols with objcopy.

              Symbols names before compilation can be influenced with the preprocessor by naming a macro with the same name, which essentially renames the symbol. For the mentioned conflict of preprocessor names (aka. macros), I see no other way short of modifying the code or undefining/redefining. Most people also use a build system which can trivially call out to sed, before invoking the compiler.

        • usrnm 2 days ago

          > and the compiler gives a warning/error about the redefinition

          That's if a macro conflicts with another macro, the real fun begins when a macro conflicts with something else in your code, and suddenly a piece of your code gets transparently replaced with something completely different. Granted, in most cases the result won't compile and you'll just spend some time scratching your head and staring at bizarre error messages, but one day you might get especially lucky and it will compile. Good luck debugging that.

          • 1718627440 2 days ago

            Fair enough, but I wouldn't call this name conflict, this sounds more like incompatible code behaviour.

            • jasode 2 days ago

              >, but I wouldn't call this name conflict, this sounds more like incompatible code behaviour.

              It literally is a name conflict. It's not a DEBUGGER SYMBOL type of name conflict but it's still a name collision. A famous example of a macro name conflict is Microsoft windows.h ntdef.h min() max():

              https://www.google.com/search?q=Microsoft+windows.h+min+max+...

              The "windows.h" is not "incompatible" code. It just has a name conflict that needs a workaround.

              • 1718627440 2 days ago

                But that's the kind of thing I addressed in my ancestor comment: a classic problem with different names clashing. You solve that by putting the translation unit boundaries somewhere else, or by undefining. Nothing else is pointed our in the Stackoverflow post appearing in your posted search query.

                It sounds a bit like some people have poor macro hygiene. I thought it's standard to just undefine all macros immediately after use.

  • juliangmp 2 days ago

    Conflicts with symbol names are a thing yes, but if I use some open source library I don't have to care about how they named their translation units. Header files might clash, which is also bad design IMO, so the reasonable thing and what I've made my default is to have a subdirectory with the library name in the include path (I.e. inc/MyLib/foo.h instead of inc/foo.h).

muststopmyths 2 days ago

From comments in the blog post

>This is not a goal. Module files are essentially better PCH, they are not meant to be a stable artifact. Consumers compile the module files from the library's interface files as needed.

That's not what I was expecting (since I haven't looked into modules too carefully). Seems counterintuitive. Today I can download an external library's pre-built artifacts and link them as long as they are compiled with the same compiler family for my architecture, etc.

This seems to mean you can't import pre-compiled modules of such a library.

OTOH, for large game projects you also want to compile third-party libs from source at least once to make sure you don't end up in the wrong branch of the debug/release/x64/x86/DLL/static maze.

So maybe it's a non-issue for most projects. You get the code, compile it once and store the artifact for future use.

Still seems a bit restrictive to me. I would have expected modules to be like DLL/.so so you could use them at your own peril if you wanted to do something quick/dirty.

Panzerschrek 2 days ago

It seems for me that adding modules into C++ was a mistake. The old-style approach with includes wasn't ideal, but it was well understood and all its downsides and pitfalls were well known.

Than modules were standardized and this happened in a very strange way. Usually major features are already implemented at least in some compilers before being standardized, but with modules it wasn't the case. It was in 2020, it's now 2025 and they aren't fully implemented and tested in all major compilers and it's unclear how long one need to wait to be able to use them.

Modules are also very problematic, as the article above shows. They didn't solve many C++ problems with multiple translation units management, like compilation speed. Moreover they added new problems atop of old ones. And managing dependencies may become ever more painful, because some dependencies use old-style includes and some use modules instead (xkcd 927).

HarHarVeryFunny 2 days ago

IMO module names should be the same as the namespace of objects exported by the module (more like Modula-2). I've never used C++20, but modules do seem a bit of a mess.

Globally unique namespace names are needed to be able to differentiate the same name used in multiple namespaces, but of course are potentially a problem if you don't have control over them.

It might occasionally be useful if there was a workaround to resolve namespace clashes by doing something like:

namespace foo {

#include "foo/module.h" // namespace Module

using Module; // Module.x is now foo.x

}

namespace bar {

#include bar/module.h" // namespace Module

using Module; // Module.x is now bar.x

}

Or, we could invent a new syntax like "import foo/module as foo".

But AFAIK there is no way to then tell the linker to rename symbols to match (e.g. -l foo/module.o as foo -l bar/module.o as bar).

  • 1718627440 2 days ago

    > But AFAIK there is no way to then tell the linker to rename symbols to match (e.g. -l foo/module.o as foo -l bar/module.o as bar).

    Renaming symbols is done with objcopy. From objcopy(1):

        --redefine-sym old=new
               Change the name of a symbol old, to new.  This can be useful when
               one is trying link two things together for which you have no
               source, and there are name collisions.
dlivingston 2 days ago

C++ modules seem like one of those things worth staying far, far away from. I wish they worked well because it would be a huge boon to modernizing C++. But from what I've seen, it's a dumpster fire. The spec is too broad and ill-defined. The compilers have gone to herculean lengths to implement it regardless, and MSVC is the only compiler with full support (for a C++20 feature, mind you). [0]

Libraries aren't implementing it. There's no `cargo`-like tooling for installing modules (AFAIK).

Can the C++ committee revert or refine the modules spec? Has anything like that been done before?

[0]: https://arewemodulesyet.org/tools/

  • m-schuetz 2 days ago

    In JS, modules were a massive improvement pretty much from day one. They were fairly quickly adoped and worked well. It's been a huge quality-of-life improvement, especially with the latter addition of import maps.

    I just wish we'd get working, well-supported modules like that for C++. I tried them once, but support was abysmal and I won't touch them again until they work nicely everywhere.

    • pjmlp 2 days ago

      To be fair, only thanks to JavaScript/TypeScript compilation and polyfills to AMD and CJS pseudo modules approach, only recently has nodejs supported ES6 modules without having to deal with switches.

      • m-schuetz 2 days ago

        I've been using modules in nodejs for a very long time. What sucked initially was that you had to use a command line flag at first, and it still sucks that you have to use the mjs extension. Still, those are minor issues compared to the issues modules face in C++. And in browsers, modules worked nicely almost from the start, and since import maps you don't even need to use any kind of build system amymore.

        • pjmlp 2 days ago

          Likewise I have been using C++ modules for my C++ hobby coding since VS 2019 prototype introduction, despite all the warts.

          Nowadays, with exception of header units, VC++ and clang alongside MSBuild and CMake/ninja are pretty much usable for anyone that is able to stick to a specific platform.

          I don't consider still fighting with build tools options in 2025 to make a pleothora of npm dependencies happy to run under nodejs a minor issue.

  • cjfd 2 days ago

    Yes, reverting has happened. extern templates have been removed.

    • pjmlp 2 days ago

      Only because outside EDG, no one else has bothered to implement them.

      Another example is the GC introduced in C++11, likewise no one made use of it.

      VC++, clang and GCC have implemented modules, granted there are still bugs to iron out.

    • maattdd 2 days ago

      export template extern still exists.

  • whstl 2 days ago

    I completely disagree. I am currently working on a large C++ project with modules and the developer experience is amazing.

    As always, the problems are always with 3rd party libraries that require special handling when compiling, but that was always the case.

    We could have off-the-shelf tooling as good as Cargo etc today, if it weren't for those special cases. Myself I just use a simple script.

    • RossBencina 2 days ago

      > As always, the problems are always with 3rd party libraries that require special handling when compiling, but that was always the case.

      I'm not sure what you mean here. Could you explain please?

      • whstl 2 days ago

        The only extra work I had to do in this modules-only project was not related to modules at all, but rather when integrating some third-party libraries, for a diversity of reasons.