Two weeks back, I blogged about C++ modules, and why we so desperately need them. Now I have actually played with the implementation in Visual Studio 2017, and I want to share my findings.
The Files
My example consists of four files in two “components”, i.e. one library and one executable. The executable only has one file, main.cpp
:
import pets; import std.core; import std.memory; int main() { std::unique_ptr<Pet> pet = std::make_unique<Dog>(); std::cout << "Pet says: " << pet->pet() << std::endl; }
The library consists of three files. First is pet.cpp
, which contains the abstract base class for all pets:
import std.core; module pets.pet; export class Pet { public: virtual char const* pet() = 0; };
Then there is dog.cpp
– our only concrete implementation of that base class (yes, I’m not a cat person).
module pets.dog; import std.core; import pets.pet; export class Dog : public Pet { public: char const* pet() override; }; char const* Dog::pet() { return "Woof!"; }
Notice they each define their own submodule. Finally, there is interface.cpp
, which just cobbles those submodules together into one single “parent” module:
module pets; export module pets.pet; export module pets.dog;
You can get the full source code including the CMake setup at our github repository. I was not able to get the standard library path setup automated so far, so you probably want to adjust that.
Discussion
There are no headers at all, which was one of my goals of laying it out like this. I think that alone means an enormous increase in productivity.
The information that was previously in the header files is now in .ifc
files that the microsoft compiler generates automatically from the module definitions.
When trying this out, a couple of things stood out to me:
- Intellisense does not work with the new keywords yet.
- The way I used it, interface.cpp needs to be compiled after pet.cpp and dog.cpp, so that the appropriate .ifc file exists. Having an order dependency like that within a single library is a new challenge.
- I was not able to use the standard lib in the library. That would compile, but not link.
- Not having to duplicate the function declaration feels very strange in C++.
- There are a lot of paradigm changes required. For example, include paths are a thing of the past – you will need to configure correct module search paths in the future.
- We will need to get the naming straight: right now, “modules” is already used as a “distinct software component”. The new meaning is similar, but still competes with it. since the granularity is no longer so flexible. I already started using “components” as a new word for the former.
What are your experiences with modules so far? Do you have another way of composing modules? I really like to hear about it! I think the biggest challenge right now is how to use these new possibilities to improve the design of bigger C++ projects.