Adding methods changes the vtable layout so there's no way to not recompile all the dependents. There's no solution to this unless private functions are guaranteed to not be virtual.
There isn't that much work the compiler should need to do. Ideally, a clever compiler could just update the vtables in some intermediate representation of the program and re-emit the binary. The C++ compiler today is so insanely wasteful - edit one header file and the compiler re-parses all the header files N^2 times. It should be possible to make a compiler thats way faster than any C++ compiler today.
Of course, the elephant in the room is the C++ preprocessor. I haven't looked too closely into cppfront, but if I had the chance, I'd give the C macro system a bullet.
My favorite "macro" system by far is zig's comptime, which is beautiful and elegant. Zig code can simply elect to be executed in the compiler instead of at runtime. For example, here's how the print() function compiles in zig. Its a thing of beauty:
> The C++ compiler today is so insanely wasteful - edit one header file and the compiler re-parses all the header files N^2 times. It should be possible to make a compiler thats way faster than any C++ compiler today.
Well, yeah, that's the problem that modules are supposed to solve. (AFAIK the only fully C++20-standard-compliant implementation of modules is in MSVC, although even Clang modules are adequate for drastically reducing compile times.)
You are still going to have to recompile all your dependent compilation units if the vtable layout changes, as mentioned elsewhere, since all of your callsites have to reflect any changes to vtable lookups.
> My favorite "macro" system by far is zig's comptime, which is beautiful and elegant. Zig code can simply elect to be executed in the compiler instead of at runtime. For example, here's how the print() function compiles in zig. Its a thing of beauty:
How is this different from constexpr / consteval in C++?
std::format (introduced in C++20) is implemented in a similar fashion in that the format string is checked at compile-time (number of args, types, etc), so there's no good reason why C++ couldn't have a print function that behaves the same way and is validated at compile-time [0]. Libraries such Abseil and folly certainly provide this.
[0] It seems that C++23's std::print is not that function, oddly enough.
In typical c++ manner, we can’t have nice things because {obscure internal technicality that don’t impact the user in any way whatsoever}$. As a user I don’t care what a vtable is. Just make it work. Other languages don’t have this problem.
During release builds sure, optimize away with LTO and whatever is needed to make it vroom. During development, waiting several minutes for a minor private function update is just absurd.
C++ is designed for good performance. Solving ABI problems permanently usually means an extra layer of indirection, which hurts performance.
There are also concerns about what you can link against or not once you modify the ABI of widely used types. This is of real concern at least for closed-source software or software that just cannot be recompiled.
I am not saying it should be the right choice, some of that software is legacy. I just say this is a real concern.
As for the private function. You can use a pimpl and use a private (on the cop file instead of header) and use that, for example, in many cases. This keeps compile time down.
Yes, there are solutions, and the simplest one is replace the direct vtable lookup with an indirect one where the methods are referenced not by their numeric offsets in the vtable but via their symbolic names and the offset resolution is performed via a separate lookup table – not that dissimilar from how it is done in ELF shared libraries.
All of them will result in incurring a performance penalty, either at the runtime, or at the start-up time, or in the compiler/linker, and memory blowouts. But it will solve the recompilation problem.
Um... isn't that guaranteed? What would it mean for a private function to be virtual? It can't be overridden by a different implementation in a child class...
Yes, you can have a private virtual member function, and it can be overridden in a child class (unless declared final), apparently.
I too thought that sounded insane, so I just looked it up. I've been programming C++ for twenty five years and the thought of wanting to do this have never ever occurred to me...
Child classes can override private member functions in their parent class.
Making all virtual functions private is the better way to implement inheritance: it separates implementation from interface, allows for common functionality to be moved to the base class without requiring gymnastics in each and every derived class, and even lets you simplify the public interface to reduce compile times.
Try it, you'll like it. You may never go back to writing Java in C++.
Of course, the elephant in the room is the C++ preprocessor. I haven't looked too closely into cppfront, but if I had the chance, I'd give the C macro system a bullet.
My favorite "macro" system by far is zig's comptime, which is beautiful and elegant. Zig code can simply elect to be executed in the compiler instead of at runtime. For example, here's how the print() function compiles in zig. Its a thing of beauty:
https://ziglang.org/documentation/master/#Case-Study-print-i...