NHacker Next
  • new
  • past
  • show
  • ask
  • show
  • jobs
  • submit
In C++ modules globally unique module names seem to be unavoidable (nibblestew.blogspot.com)
HelloNurse 128 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 128 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 128 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 128 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 127 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 127 days 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 128 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 128 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 128 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 127 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 128 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 128 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 128 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 127 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 128 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 128 days ago [-]
Fair enough, but I wouldn't call this name conflict, this sounds more like incompatible code behaviour.
jasode 128 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 127 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.

magicalhippo 128 days ago [-]
> But the symbol names don't matter after linking.

C++26 will get run-time reflection from what I can gather[1], in which case symbol names will matter after linking, no?

[1]: https://learnmoderncpp.com/2025/07/31/reflection-in-c26-p299...

theICEBeardk 128 days ago [-]
No it is gaining compile time reflection. But RTTI has been a thing for a long time.
juliangmp 128 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 128 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 128 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 128 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 127 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 128 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 128 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 128 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 128 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 128 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 128 days ago [-]
Yes, reverting has happened. extern templates have been removed.
pjmlp 128 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 127 days ago [-]
export template extern still exists.
whstl 128 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 128 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 128 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.
127 days ago [-]
Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact
Rendered at 03:51:02 GMT+0000 (Coordinated Universal Time) with Vercel.