4 ms·
And yet C, an even lower-level language, achieves the same effect without the duplication of PIMPL. You just forward-declare a struct, and declare functions th
by comex 2y ago
And yet C, an even lower-level language, achieves the same effect without the duplication of PIMPL. You just forward-declare a struct, and declare functions that accept pointers to it: the header doesn't need to contain the struct fields, and you don't need to define any wrapper functions. Technically you can do the same in C++. But in C++ to make an idiomatic API you need methods instead of free functions, and you can't declare methods on forward-declared classes. Why not? Well, I can imagine some reasons… but they have more to do with C++'s idiosyncrasies than any fundamental limitation of a low-level language.
The C++ committee could address this, but instead they seem to want to pretend separate compilation doesn't exist. (Why are there no official headers to forward-declare STL types, except for whatever happens to be in <iosfwd>?) Then they complain about how annoying it is to preserve ABI stability for the standard library, blaming the very concept of a stable ABI [1] [2], all while there are simple language tweaks that could make it infinitely more tractable! But now I'm ranting.
[1] https://cor3ntin.github.io/posts/abi/ https://cor3ntin.github.io/posts/abi/
[2] https://thephd.dev/binary-banshees-digital-demons-abi-c-c++-help-me-god-please https://thephd.dev/binary-banshees-digital-demons-abi-c-c++-...
- wakawaka28 2y agoFirst of all, comparing C to C++ in this way is silly, because C++ is a very different language. But there are some similarities. > You just forward-declare a struct, and declare functions that accept pointers to it: the header doesn't need to contain the struct fields, and you don't need to define any wrapper functions. Those functions would be more verbose because they must contain an explicit `this` equivalent pointer. This would have to be repeated at every single call site. So it's not really helping. You don't need wrapper functions for PIMPL. You can have them if you think it's worthwhile, of course. >Technically you can do the same in C++. But in C++ to make an idiomatic API you need methods instead of free functions, and you can't declare methods on forward-declared classes. Why not? There are good technical reasons why you can't tack member functions into the interface of a forward-declared function. There would be nowhere for that information to go, if nothing else. I think I heard a talk about adding new metaprogramming features to C++ that might address this in like C++26, but anyway it's not a significant problem to simply avoid the problem I think you can probably make some template-based thing that would automate implementing the wrappers for you. But it would be a convoluted solution to what I consider a non-problem. >The C++ committee could address this, but instead they seem to want to pretend separate compilation doesn't exist. (Why are there no official headers to forward-declare STL types, except for whatever happens to be in <iosfwd>?) Most of the STL types that people need are based on templates. It does not make sense to forward-declare those. I just don't see a use case for forward-declaring much besides io stuff and maybe strings. >Then they complain about how annoying it is to preserve ABI stability for the standard library, blaming the very concept of a stable ABI [1] [2], all while there are simple language tweaks that could make it infinitely more tractable! But now I'm ranting. There seems to be a faction of the C++ committee that does not share the traditional commitment to backward compatibility. They have gone so far as to lobby for a rolling release language, which is guaranteed to be a disaster if implemented. I think wanting to break ABI might be a sign of that. Let's hope they use good judgement and not turn the language into an ever-shifting code rot generator. Keep in mind, there may be ABI breakage coming from your library provider anyway, on top of what the committee wants. So it's not necessarily such a cataclysmic surprise as something you're supposed to plan around anyway. ABI stability between language standards is mostly a concern for people who link code built with different C++ standards (probably, a lot of code). It wouldn't be the end of the world if you had to recompile old code to a newer standard, but it might generate significant work.
- gpderetta 2y ago> There are good technical reasons why you can't tack member functions into the interface of a forward-declared function. Are there? You could have a class decorator to mark a definition as incomplete and only allow member functions, types and constant definitions: // in Foo.h incomplete struct Foo { public: Foo(); Foo(const& Foo); void frobnicate(); }; // in foo.cc struct Foo { // redefinition of incomplete structs is allowed public: Foo(){...} Foo(const& Foo) {...} void frobnicate(){...} private: void bar() {...} int baz; string bax; }; edit: there are also very good reasons to fwd declare templates. You might want to add support in your interface for an std template without imposing it to all users of your header. In most companies I have worked, we had technically illegal fwd headers for standard templates.
- wakawaka28 2y ago>Are there? You could have a class decorator to mark a definition as incomplete and only allow member functions, types and constant definitions: C++ already has a way to do this via inheritance, even multiple inheritance. I suppose some of the same machinery used for inheritance could be repurposed for partial class definitions but it is unnecessary. Edit: I think I overlooked something here at first glance. Yes it might be nice to have a public partial definition of a class and a private full definition. But the technical reason you can't have this is that using a class in C++ requires knowing its memory characteristics. If that information does not come from the code, then it must come from somewhere else like a binary. Maybe the partial definition could be shorthand for "use PIMPL" but I haven't thought through all the ways it could go wrong, such as with inheritance. >edit: there are also very good reasons to fwd declare templates. You might want to add support in your interface for an std template without imposing it to all users of your header. In most companies I have worked, we had technically illegal fwd headers for standard templates. I have never seen illegal forward declaration headers. Not at any company I've worked at, nor in any open-source project. I don't think there is a reasonable value proposition to doing that. What kind of speedup are you expecting from that? >You might want to add support in your interface for an std template without imposing it to all users of your header. This sounds good in theory but in practice, most interfaces I've seen use the same handful of types or std headers, so it can't be avoided and furthermore you'd be forcing everyone to bring their own std headers every time (and probably forget why they ever included them in their own code, in the first place). You'd be talking about a lot of trouble to maybe save one simple include, and introducing a lot of potential for unused and noisy includes elsewhere.
- uecker 2y agoIt is indeed one of the most grotesque language design errors C++ did early on.