cyboryxmen had created a post a few months ago suggesting switching to functional programming and made a claim about it's expressiveness over object oriented programming and other things.
There are benefits to functional programming when it comes to multi-threading since the main focus of functional programming is immutability. Instead of changing the state of an object, you just create a new object with the new state and copies of the old state that didn't change. You have to retrain your brain to always have return values from functions, in this way, none of the threads ever share resources which makes multi-threading faster by not requiring locks which causes threads to wait at a red light while the thread that acquired the lock has the green light.
Functional programming does require more memory since you aren't just reusing the same object. It is also slower in single threaded applications from all the copying.
Think about this:
Code: Select all
class Entity{
public:
Entity() = default;
// The rest of the members are default initialized in class at the bottom
Entity( float posX, float posY )
:
x( posX ), y( posY )
{}
Entity update( float dt )const {
// Calculate new velocity
const float newVelX = vx * ( dt * speed );
const float newVelY = vy * ( dt * speed );
// Calculate new position
const float newPosX = x + newVelX;
const float newPosY = y + newVelY;
// I use a lambda here so I can create a const variable, I love lambdas
const Color newColor = []( float hlth ){
if( hlth > 70.f )
return Colors::Green;
else if( hlth > 30.f )
return Colors::Yellow;
else
return Colors::Red;
}( health );
return Entity( newPosX, newPosY, newVelX, newVelY, speed, health, newColor );
}
float getPositionX()const{ return x; }
float getPositionY()const{ return y; }
float getVelocityX()const{ return vx; }
float getVelocityY()const{ return vy; }
float getHealth()const{return health; }
Entity setPosition( float posX, float posY )const{
// Most of the set functions will follow same pattern
return Entity{ posX, posY, vx, vy, speed, health, color };
}
Entity setVelocity( float velX, float velY )const{
return Entity{ x, y, velX, velY, speed, health, color };
}
Entity setSpeed( float spd )const{
return Entity{ x, y, vx, vy, spd, health, color };
}
Entity takeDamage( float amount )const{
return Entity{ x, y, vx, vy, spd, health - amount, color };
}
Entity boostHealth( float amount )const{
return Entity{ x, y, vx, vy, spd, health + amount, color };
}
void draw( Graphics& gfx )const{
gfx.drawBlock( int( x ), int( y ), int( x + size ), int( y + size ), color );
}
private:
// Outside world probably doesn't need to instantiate an Entity like this
Entity(
float posX, float posY,
float velX, float velY,
float spd,
float hlth,
Color clr )
:
x( posX ), y( posY ),
vx( velX ), vy( velY ),
speed( spd ),
health( hlth ),
color( clr )
{}
private:
static constexpr float size = 32.f;
float x = 0.f, y = 0.f;
float vx = 0.f, vy = 0.f;
float speed = 240.f;
float health = 100.f;
Color color = Colors::Black;
};
The second constructor seems like it would be the only real useful one for outside world access. The rest of the members are initialized to defaults in class. They can be changed, but it will create a new instance each time you call one of the set functions.
This way also allows chaining calls to set functions so that at the end, you get an Entity that is initialized the way you want.
Now, how to write a program where you never directly modify objects and always create new objects I'm not entirely sure.