C++ without classes
This commit is contained in:
		
							parent
							
								
									7cf5fbf843
								
							
						
					
					
						commit
						59bdeb93ac
					
				
					 1 changed files with 88 additions and 0 deletions
				
			
		
							
								
								
									
										88
									
								
								content/programming/cxx-without-classes.tree
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								content/programming/cxx-without-classes.tree
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,88 @@
 | 
			
		|||
%% title = "C++ without Classes"
 | 
			
		||||
 | 
			
		||||
- one thing I often see in people's code in C++ is putting _everything_ into a class.
 | 
			
		||||
 | 
			
		||||
    - there's nothing wrong with putting code that actually, y'know, _uses the class_, in the class, but it irks me when I see things like helper functions and other implementation details being in the class.
 | 
			
		||||
 | 
			
		||||
        - private functions have the unfortunate consequence of being part of the public header, even though they are implementation details!
 | 
			
		||||
        this means if you edit them, you have to edit both the .cpp implementation file, as well as the .h header.
 | 
			
		||||
 | 
			
		||||
- which is precisely what C++ without Classes is about.
 | 
			
		||||
since updating method signatures is a pain in the ass... just don't do it!
 | 
			
		||||
 | 
			
		||||
    - declare all your fields public, and let `static` functions within your `.cpp` file work the magic.
 | 
			
		||||
 | 
			
		||||
        - and here you might say: "but I don't _want_ to have these fields public! it breaks encapsulation!"
 | 
			
		||||
        to which I respond: so make your data structure private!
 | 
			
		||||
 | 
			
		||||
- example of C++:
 | 
			
		||||
 | 
			
		||||
#### world.h
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
struct World
 | 
			
		||||
{
 | 
			
		||||
    // ... fields ...
 | 
			
		||||
 | 
			
		||||
    void update(const Update_Context& context);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void update_aims(const Update_Context& context);
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### world.cpp
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
void World::update(const Update_Context& context)
 | 
			
		||||
{
 | 
			
		||||
    update_aims(context);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void World::update_aims(const Update_Context& context)
 | 
			
		||||
{
 | 
			
		||||
    // ...
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
- example of C++ without Classes:
 | 
			
		||||
 | 
			
		||||
#### world.h
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
struct World
 | 
			
		||||
{
 | 
			
		||||
    // ... fields ...
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void update(World& world, const Update_Context& context);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### world.cpp
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
static void update_aims(World& world, const Update_Context& context)
 | 
			
		||||
{
 | 
			
		||||
    // ...
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void update(World& world, const Update_Context& context)
 | 
			
		||||
{
 | 
			
		||||
    update_aims(world, context);
 | 
			
		||||
    // ...
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
    - suddenly, the publicly available part of `world.h` has gotten smaller---there's one method less.
 | 
			
		||||
    the implementation detail `update_aims` does not leak into the header; we don't have to update the signature in two places if we ever want to change it, and it does not cause a recompilation if we edit it.
 | 
			
		||||
 | 
			
		||||
    - I took the `update` method out of the struct to signal the lack of coupling.
 | 
			
		||||
    _anyone_ can do what `update` does; it doesn't matter.
 | 
			
		||||
    every function is at the same level as the struct itself.
 | 
			
		||||
 | 
			
		||||
    - in my own code, outside this contrived example, I also put functions related to a data structure in a namespace---in this case, `update(World&, const Update_Context&)` would be `world::update(World&, const Update_Context&)`.
 | 
			
		||||
    this is purely a stylistic preference---I like the extra explicitness over leaning on overloads.
 | 
			
		||||
 | 
			
		||||
- I've been enjoying this style a lot.
 | 
			
		||||
it takes edge cases like `this` out of the language, and results in simpler, more easily editable code.
 | 
			
		||||
so I wholeheartedly recommend giving it a try!
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue