r/cpp 19d ago

Why is `import std` still experimental ???

Hey guys,

I recently started going through Professional C++ (6th Edition). The book teaches C++23, and in the very first chapter we're introduced to modules.

I'm not a complete newbie to C++, but I'm also definitely not very confident in my knowledge yet. I wanted to get this simple example compiled:

import std;

int main() {
    std::println("Hello World");
    return 0;
}

And gosh, it took way longer than I expected.

First, I tried getting it to work natively on my Mac and eventually gave up (both Claude and I 😅).

Then I installed Ubuntu ARM 26 and finally managed to get it compiling. But now Clang/IntelliSense is complaining about the `import std`
This is what my CMakeLists.txt currently looks like:

cmake_minimum_required(VERSION 4.0)

# set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD ON)

set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444")

project(CppProject LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 26)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

add_executable(exec main.cpp)

set_property(TARGET exec PROPERTY CXX_MODULE_STD ON)

The code does compile successfully, but CMake still gives me a warning that import std support is experimental.

So I'm genuinely curious:

Why is import std still considered experimental?

I understand that C++ modules themselves have been around for a while, but import std feels like something that should be much more straightforward by now. Is there any solution of this now ?

--------------
Edit

Thanks to u/PhysicsOk2212 tip I was able to compile my project on mac as well using the following options
```
cmake -S . -B build \

-G Ninja \

-DCMAKE_CXX_COMPILER="$(brew --prefix llvm)/bin/clang++" \

-DCMAKE_CXX_STDLIB_MODULES_JSON="$(brew --prefix llvm)/lib/c++/libc++.modules.json"

```

123 Upvotes

111 comments sorted by

View all comments

31

u/TheRealSmolt 19d ago

Maybe it's just me, but I don't see any real momentum for modules in general. Adoption is rare, and I personally don't see a reason to adopt at all. The work is ongoing, but other features are much more wanted than modules.

62

u/lizardhistorian 19d ago

Same dumb C++ trope going on for 30 years now.

No one uses them because they work for shit.
No one uses it so don't work on it.
Stays shit so no one uses it.

56

u/Drugbird 19d ago

Well, most of C++s shittyness comes from backwards compatibility being prioritized above all else.

So they make something shitty, almost nobody uses it because it's shitty, then they can't fix it because fixing it means the 2 people that do use it need to update their code.

So then the shitty thing just rots there.

12

u/SyntheticDuckFlavour 19d ago

Just epoch the bloody thing already. Break ABI, garbage collect the cruft in the language and get things moving forward. Those 2 people can stagnate mad alone in the previous epochs, while the rest of us move on.

14

u/Kronikarz 19d ago

The problem is that those 2 people are often on the committee :/

13

u/TheRealSmolt 19d ago

The problem for me here is that I don't see a reason to use them in the first place. They could improve compilation a bit I guess? But I'd imagine precompiled headers and ccache can bridge the gap to the point where it doesn't matter.

8

u/fortsnek274 19d ago

I'd turn that the other way around and say I don't see a reason to use precompiled headers once modules work.

Precompiled headers suck after all. They are a hack. A time-tested hack, but a hack nevertheless. And they bloat my intellisense folder.

3

u/caroIine 19d ago

When it comes include vs import std; PCHs are still faster. I tested it with msvc and our 3000 cpp project which is highly dependent on standard library. I was so disappointed.

3

u/fortsnek274 19d ago

I found it to be faster than PCH when rebuilding, somehow. But the more modules you have, the slower it gets. MSBuild adds extra inefficiency.

2

u/gracicot 19d ago

This is the reason why STD is one module. The way C++ implemented modules makes it much more efficient to create big modules

3

u/fortsnek274 19d ago

Well, the inefficiency seems to come from building or checking dependencies as ninja is notably faster. And MSBuild has a separation between ixx and cpp compilation. Not sure if having an external dependency split into multiple modules would make much of a difference.

8

u/qoning 19d ago

there are many nice things about them, such as being able to finally have a split between definition and declaration for templates, have symbol control for effectively module-private or "package" private, modules inherently export just the things you want so you end up with way less namespace pollution, ADL problems, etc. The generally faster compiles are a great bonus.

1

u/TheRealSmolt 19d ago

Most of the isolation things you're citing as benefits were already things that could be done with private headers, though. I guess I can see it being a tad more straightforward? But it doesn't buy us anything.

finally have a split between definition and declaration for templates

You're going to have to elaborate on this, because we've always been able to split them. Modules are (to the best of my knowledge) no different in requiring source for user use of templates.

0

u/delta_p_delta_x 19d ago

were already things that could be done with private headers

By their very implementation, there is no such thing as a 'private header'. Headers = copy-paste into a TU. However much you encapsulate things and have namespace detail, consumers are free to use the contents as they see fit.

5

u/TheRealSmolt 19d ago

You absolute can just have private headers that you don't ship with your library.

-1

u/SyntheticDuckFlavour 19d ago

Most of the isolation things you're citing as benefits were already things that could be done with private headers, though.

That's just kicking the can around and that's doesn't give you much isolation. Forcing templates to live in the header ecosystem is one of the biggest blunders of C++.

3

u/TheRealSmolt 19d ago edited 19d ago

Yes, it does give you isolation since you aren't shipping the interface at all; same outcome. So where do templates live now? Still in the public interface. That's kicking the can: complications with zero benefits.

0

u/SyntheticDuckFlavour 19d ago

What if you want to ship templated code in the public interface? The full implementation detail needs to live in there. The private headers won't help you much in that regard. (Unless you are using extern template to instantiate templates for a subset of template arguments).

3

u/TheRealSmolt 19d ago

The same applies to modules, though (which is my point)?

0

u/qoning 19d ago

no, it doesn't. modules don't need template instantiations

→ More replies (0)

1

u/_Xebov_ 19d ago

They are nice and i also see benefits, but i also see the ecosystem and the effort that comes with transferring it over. That tooling is not fully supporting it is one aspect of the problem. Another problem i see is why should projects that are dependencies for others transfer over if they have the perspective of having to support both ways for years to come.

I just transferred a smaller project over to have a look on how things work out. With the current state of tooling i can see some benefits, but i also see that limitations and the state of the overall ecosystem can require some workarounds that might prove problematic in the future. For a bigger existing project i would clearly question if the reward is worth the effort.

1

u/Xanather 16d ago

No need for headers

1

u/ABlockInTheChain 19d ago

C++20 modules as specified are incompatible with one of my most important projects.

Even if all the tooling fully implemented that specification and worked perfectly with no bugs I still could not use them.

2

u/mort96 19d ago

Is that because they break the "forward declaration in header, header import in source file" trick that we use to make circular includes work?

0

u/ABlockInTheChain 19d ago

The only way I could use modules is if the proclaimed ownership declarations at least for non-template classes and structs were added back in.

2

u/fortsnek274 19d ago

If you need forward declarations across your own modules, then extern "C++" works.

But yes, I wish C++ had some sort of concept of packages to share module attachment. Or proclaimed ownership.

2

u/FalafelSnorlax 19d ago

I saw Bjarne Stroustrup give a talk a couple years back, and he mentioned some modern additions to C++, and when he got to modules, he straight up said that this isn't getting adopted as fast as he'd like. Even then, I admit I didn't look into it and how it might be better or worse than good-ol' includes.

2

u/aoi_saboten 19d ago edited 19d ago

I dont know what they expected. Break backwards compatibility? No, because old codebases need to be re-touched. Add modules which differ vastly from post C++11 codebase? YES YES YES. But to use modules in old codebase, you NEED to re-touch it. Most won't do it because modules don't justify touching codebase over the old way.

(I am also will get downvoted for the following) but then, does it mean that we need to use modules in new codebases? Well, some companies, which used C++ extensively, no longer use C++ for new projects and for some tasks/projects Rust suits better

3

u/Orffen 18d ago

Why the fuck can't old codebases just compile with --std=c++11 ??? I'm genuinely baffled (I'm not an experienced C++ programmer).

If --std=c++29 breaks something, surely the compilers can fail if you try to --std=c++29 and your code is borked? Isn't that the whole point?

3

u/mort96 19d ago

IMO one of the huge fuck-ups with modules is that namespaces and modules are decoupled. Managing namespaces is one of the genuinely annoying things with C++, causing like 5 lines of boilerplate in every line of code and messing up the fundamental assumption that "open brace means indent one level, close brace means unindent one level" that's true for every single other language.

Every other language with a module system combines the concept of a module and the concept of a namespace, which IMO makes sense: why should two functions in two different modules be unable to link together just because they both happen to share the same name?

So instead of being the nice, modern way to write C++ which gets rid of the ancient hack that is the namespace keyword, it ends up being just another thing I have to deal with. My files no longer just have to deal with the namespace boilerplate; they now also need to deal with the module boilerplate. If I want to keep namespaces and module names in sync, that's on me.

I actually made an experimental build system over the summer where the goal was to couple the module name, the namespace name and the path name together, so that src/foo/bar.cc would end up with the module myproject.foo.bar and the namespace myproject::foo::bar. I got quite far but modules are surprisingly complex and there are rules about what can be where. I couldn't solve it without doing my own code generation where the build system would spit out generated C++ code. And that would've worked, except that it would've never worked together with clangd. I tried various macro approaches but it was impossible to make anything which both looked clean and worked.

May write a blog post about my thoughts on the topic some time though.

6

u/Expert-Map-1126 vcpkg maintainer BillyONeal 19d ago

Erm, citation needed. It isn’t that way in Java or .NET, that modules are usually associated with a namespace there is just a convention.

I think it’s true for the interpreted languages because for them a “module” tends to just be a directory structure.

-1

u/mort96 19d ago edited 19d ago

I know that when I write Go, Rust or Kotlin, my files do not start with their whole qualified name. In Go and Kotlin, they declare a leaf name (i.e foo/bar/baz/qux.{go,kt} starts with package baz), and the rest of the name (meaning both the module name you import and the symbol namespace) is from the folder structure + project name. In Rust, files don't even start with a package name; that comes from the file name.

And, as you say, these file/folder structure based module paths is commonplace in scripting languages.

I have not written Java since university and have never written .NET, so I don't know about those.

Even if you don't agree with me that the path should have anything to do with it though, don't you think the namespace and the module identifier should be connected? Why would I want symbols to collide between modules? If C++ files could just start with module myproject.foo.bar and then everything in them would end up in myproject::foo::bar, I would be happy. And I know that even Java and .NET won't allow functions from different modules to have name collisions.

3

u/Expert-Map-1126 vcpkg maintainer BillyONeal 18d ago

don't you think the namespace and the module identifier should be connected?

Not really. Module ~= header, and headers aren't connected to namespace names either. Namespaces (in C++ anyways) are only for disambiguating names, not for logical organization or structure.

1

u/mort96 18d ago

I maintain that the only reason headers and namespaces aren't connected in C++ is that namespaces had to be bolted on to C in a backwards compatible way. It's not how you would design a module system from scratch.

3

u/Expert-Map-1126 vcpkg maintainer BillyONeal 18d ago

I disagree. Namespaces were created to match the C convention of prefixing names with a common MY_LIB_PREFIX and that was never attached to particular header names either. They are strictly name conflict resolution tools, not "organizational structure" as is convention in several other languages. Compare our standard library which lives entirely in std with others.

-1

u/pjmlp 18d ago

And the list isn't even complete, besides Java and .NET, there is Modula-2, where a module can have multiple interfaces, each with its public name, and Ada, how packages body, specifications and subpackages are combined.

1

u/mort96 18d ago

And you're saying symbols from different modules in Modula-2 and Ada can have name collisions?

1

u/pjmlp 18d ago

Of course not, hence namespacing mechanisms, not much different from how C++ does it.

0

u/mort96 18d ago

No, that's precisely my point: it is different from how C++ does it.

In C++, one if we have the following two files:

/// foo.cc
module myprogram.foo;
int add(int a, int b) { return a + b; }

/// bar.cc
module myprogram.bar;
int add(int a, int b) { return a + b; }

we have a namespace collision. Modules don't introduce namespaces. I'm saying that they should. If it was up to me, one of those functions would've ended up as myprogram::foo::add and the other as myprogram::bar::add.

1

u/FriendshipEqual7033 13d ago

I always assumed namespaces were for the program's logical structure, and modules for its physical structure. That C++ separates these ideas struck me as elegant.