3 ms·
> strikes me as something of a language flaw that without pimpl any addition/removal/ modification of private member functions, or even renaming of private mem
by rewmie 3y ago
> strikes me as something of a language flaw that without pimpl any addition/removal/ modification of private member functions, or even renaming of private member variables triggers full recompilation of every source file that needs to use a particular class.
It is not a language flaw. C++ requires types to be complete when defining them because it needs to have access to their internal structure and layout to be in a position to apply all the optimizations that C++ is renowned for. Knowing this, at most it's a design tradeoff, and one where C++ came out winning.
For the rare cases where these irrelevant details are relevant, C++ also offers workarounds. The pimpl family of techniques is one of them, and type erasure techniques are also useful, and protocol classes with final implementations are clearly another one. Nevertheless, the fact that these techniques are far from being widely used demonstrates that there is zero need to implement them at the core language level.
- jstimpfle 3y agoThere isn't a good reason why private methods should be exposed in the header. This makes refactoring the class implementations much more of a pain in the butt than plain structs + global functions. You can always add internal functions to the implementation without causing a reimplementation of all dependencies, while you can't do the same with private methods. And private methods aren't exactly "rare cases". The situation is bad to the point that most good codebases make less use of classes, and many average code bases avoid adding private methods and resort to code duplication to a degree.
- wizofaus 3y agoPrivate methods do need to be in some sort of privileged "single source of truth" for the class definition though - if you were permitted to have a partial class definition in the "public" header file that defined public/protected methods plus all variables, then a single other partial class definition in a separate header or compilation unit it would go some easy towards solving the issue. But I still don't quite see why compilers can't make assumptions about what changes to class definitions can possibly require recompilation of other compilation units (even if it only applies at certain optimisation levels).
- jstimpfle 3y agoPrivate methods, unless they are virtual, do not to my knowledge have any bearing on the ABI of a class, nor need they be known to users of the class, so listing them in the class declaration seems nonsensical. The reason why they have to be listed anyway could be 1) a vague idea of "consistency" with e.g. public methods and generally the enforcing access control only centrally from the class declaration 2) the idea of overriding the implementation in an inherited class. As far as I'm concerned, both are bad reasons to impose such an annoying limitation to the user of the language.
- wizofaus 3y agoThe whole point of private methods is that they have privileged access to the implementation details of the class (i.e. private member variables and other private methods). So there still needs to be a restricted place they can be defined - what are you proposing?
- jstimpfle 3y agoMark the function as part of the implementation of the class. Simply prefixing the name with the name of the class (as it's already done) could be enough. Optionally request a keyword. I don't see what's the big deal, the saying is to guard against Murphy not Machiavelli. Or go the same route as namespaces -- mark start and end of the class implementation code (can be repeated) and nest functions inside. There are other options if we ditch the C/C++ compilation model. Though arguably that isn't just bad -- it's an extremely simple way to achieve separate compilation without requiring a separate (probably binary, compiler-specific) representation for compiled interfaces. The latter could probably speed up incremental builds considerably, but it's possibly slower for clean rebuilds because of dependencies.
- wizofaus 3y agoSo you're saying it's perfectly fine for someone to use any class from any library (including the standard library) and define their own "implementation" private methods for such classes, that then access implementation details of that class? How is that even protection against Murphy? (who sees other examples of such things and assumes that's just the "done thing"). For me, knowing that I can change the implementation details of a class and it having no possible impact on whether other code compiles or how it behaves (assuming I maintain the same "public" behaviour) is absolutely a fundamental language feature. All I'm arguing for is that compilers should be able to make the same assumption - only the private implementation details have changed, so it's unnecessary to recompile other code that happens to include the header file defining some of those implementation details.
- rewmie 3y ago> There isn't a good reason why private methods should be exposed in the header. This makes refactoring the class implementations much more of a pain in the butt than plain structs + global functions. Irrelevant. Private member functions aren't mandatory or required, and when developers decide to use them they explicitly state the class needs to export their symbols. Those developers who somehow feel strongly about private member functions are a multitude of techniques to meet their needs, such as using protocol classes and move private stuff to concrete implementations, or use non-member functions either with internal linkage or stashed in anonymous namespaces. I don't see the point of complaining that something used wrong is not being used right, while purposely ignoring the myriad of options where things are right based on your arbitrary requirements. I mean, this aspect of C++ is around for at least three decades. Don't you think that if it was a problem someone would already have noticed it?
- jstimpfle 3y agoIf you use "class" / private members, you have to use methods to access the members. That, or a friend "class" containing static methods (a namespace won't do). Private methods are annoying because you're forced to expose implementation details, and are forced to duplicate function signatures in the code. Friend classes are annoying because you still have to name them in the class declaration, and having to use them with static methods leads to stylistically inconsistent code and you end up with a weird dummy class that isn't meant to ever be instanced. AFAIK there isn't a nice way to deal with this other than simply not using private members and coding in a simple C like style. I don't think you've shown a way, either. I don't know what you mean by "protocol classes", but if you mean abstract classes with virtual methods that need to be overridden, those are a bad solution because they overhead of vtables without any technical need or benefits (unless you want runtime polymorphism and vtables are exactly the kind you want).
- diamondlovesyou 3y ago> It is not a language flaw. C++ requires types to be complete when defining them because it needs to have access to their internal structure and layout to be in a position to apply all the optimizations that C++ is renowned for. Knowing this, at most it's a design tradeoff, and one where C++ came out winning. This statement is incorrect. "Definition resolution" (my made up term for FE Stuff(TM) (not what I work on)) happens during the frontend compilation phase. Optimization is a backend phase, and we don't use source level info on type layout there. The FE does all that layout work and gives the BE an IR which uses explicit offsets. C++ doesn't allow two phase lookup (at least originally); that's why definitions must precede uses.