thoughts on C++ access modifiers
This commit is contained in:
parent
f8ca16a50d
commit
66eef2996f
|
@ -7,6 +7,12 @@
|
||||||
% id = "programming/projects"
|
% id = "programming/projects"
|
||||||
+ ## projects
|
+ ## projects
|
||||||
|
|
||||||
|
- (actually nothing here yet lol, I was about to write something here but forgot but now don't wanna delete a branch I'm gonna bring back again anyways)
|
||||||
|
|
||||||
|
% content.link = "programming/cxx"
|
||||||
|
id = "programming/cxx"
|
||||||
|
+ ## C++
|
||||||
|
|
||||||
% content.link = "programming/unreal-engine"
|
% content.link = "programming/unreal-engine"
|
||||||
id = "programming/unreal-engine"
|
id = "programming/unreal-engine"
|
||||||
+ ## Unreal Engine
|
+ ## Unreal Engine
|
||||||
|
|
45
content/programming/cxx.tree
Normal file
45
content/programming/cxx.tree
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
- design lessons from the best programming language of all time that everyone loves (not really)
|
||||||
|
|
||||||
|
+ access modifiers as labels (`private:`, `protected:`, and `public:`)
|
||||||
|
|
||||||
|
- although Java and C#'s approach to symbol privacy may be verbose, it has one great advantage: it is stateless.
|
||||||
|
|
||||||
|
- the way they're implemented in C++, it's essentially a bit more parsing state you have to keep track of
|
||||||
|
|
||||||
|
- and you know what other parsing state you have to keep track of in C++? - that's right, the preprocessor.\
|
||||||
|
access modifiers, like all tokens, are affected by the preprocessor, and you have to take that into account
|
||||||
|
|
||||||
|
- take the following example:
|
||||||
|
```cpp
|
||||||
|
class ComfyZone
|
||||||
|
{
|
||||||
|
std::vector<SoftBed> _soft_beds;
|
||||||
|
|
||||||
|
#if ENABLE_HUGS
|
||||||
|
|
||||||
|
public:
|
||||||
|
void hug(Person& person);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int _remaining_hugs = 10;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
- although quite contrived, it illustrates the problem pretty well
|
||||||
|
|
||||||
|
- (before you ask, `_remaining_hugs` needs to be always present because it has to be (de)serialized no matter if hugging functionality is compiled in. otherwise we'd get data loss.)
|
||||||
|
|
||||||
|
- we intended for `_remaining_hugs` to be private, but if hugs are enabled, it becomes public.
|
||||||
|
|
||||||
|
- this can be _very_ hard to spot if you have a big class with lots of declarations inside.
|
||||||
|
|
||||||
|
- this can be worked around by banning access modifiers from appearing in `#ifdef`s, but you have to *realize* that this might happen
|
||||||
|
|
||||||
|
- and I've seen instances of this exact thing occurring in the Unreal Engine codebase, which is *full* of long lists of declarations (made even longer by the prevalence of `UPROPERTY()`s)
|
||||||
|
|
||||||
|
- even if we didn't have the preprocessor, that access modifier is state _you_ have to keep track of
|
||||||
|
|
||||||
|
- I very often find myself needing to scroll upward after <kbd>Ctrl</kbd>-clicking on a field or function declaration, just to find out if I can use it
|
||||||
|
|
||||||
|
- (thankfully IDEs are helpful here and Rider shows you a symbol's visibility in the tooltip on hover, but I don't have Rider on code reviews)
|
Loading…
Reference in a new issue