Jump to content
  • Advertisement
Sign in to follow this  
Mafioso

Why OOP more popular than functional programming?

This topic is 2848 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Why OOP more popular than functional programming? In OOP are many cpp's/headers, everything is more complicated and harder to understand, in functional programming you only need to create a function, and run it in main.cpp, easier to know scope and debug, no complicated stuff, no inheritances, so is OOP faster? Because every open source project is made with OOP.

Share this post


Link to post
Share on other sites
Advertisement
When you treat programming data like objects, it's a bit closer to the real world, and so it becomes a bit easier to understand, as such, when working on Huge projects, (such as video games), OOP tends to be a easier to organize, not always the case, but usually.

Share this post


Link to post
Share on other sites
It depends on the scope of the project, I like working with objects because I find it easier to work out solutions to problems, like I broke down my current project into a large number of different classes and using inheritance I have created a common interface that is easier to understand for example:

All of my classes which contain something to render have a function called Draw which takes a reference to the render window as an argument (using SFML). They then use the render window to draw themselves to the screen and also update the sprite to make sure it is using the current subrect for animation/direction it is facing.

NPC's are inherited from a pure virtual class which defines the core functions (such as Draw, Update), they also have a specific function for interaction with the player which can be called through update. For example currently if the player stands close enough to a friendly NPC that is walking it will stop until the player has left the vicinity and then continue on it's way. If the player stands close enough to a hostile NPC it will leave it's path to chase after the player and if the player is far away enough it will return to it's path.

Thing's like that I don't see how I could have solved as simply using a plethora of functions which would be hard to understand, where is the ability to expand on something with a procedural program? With OOP if I want to add a new Friendly NPC I can create it with two lines of code (one to initiate a smart pointer, the other to push onto the container of smart pointers which could probably be changed down to one line I guess). With procedural I would have to create at least 18 different uniquely named variables for that NPC, and considering about half of those are classes themselves including a few which I defined myself (Waypoints for following a simple path, ImageManager for handing out pointers to images and also containing all of the various subrects to be obtained from a map)...it sort of leads into a predicament.

If you are working on a small project like pong procedural is a viable choice (albeit a little conceited in my opinion as you are creating more than one of objects, albeit with slightly different behaviour, you can still seperate the behaviour from the class by simply calling the move function from your player's input and the AI code which can be a function that makes sense) you also have to realise that depending on the language you are using, you are making use of objects whether you like it or not. "complicated and harder" isn't really a valid argument for not picking a paradigm which could be more suited for the job.

Share this post


Link to post
Share on other sites
Quote:
Original post by Mafioso
Why OOP more popular than functional programming? In OOP are many cpp's/headers, everything is more complicated and harder to understand, in functional programming you only need to create a function, and run it in main.cpp, easier to know scope and debug, no complicated stuff, no inheritances, so is OOP faster? Because every open source project is made with OOP.


As already mentioned, you mean structured programming - functional programming is something entirely different altogether!

The speed differences between OOP and structured approaches is largely negligible. It's more a matter of convenience than anything else.

A game by its very nature, is largely a data driven system - and a lot of that data can be brittle - i.e. set the wrong value, and parts of the game engine explode in a nasty mess.

Therefore if you have the ability to encapsulate data (via private/protected & getters/setters) you can minimise the possibility of those errors from occurring (how successful that is depends on your unit tests really ;)). It is also much easier to expose a public interface from classes than it with C.....

I imagine most experienced devs, if forced to program in C, would still program with an OOP approach (which is entirely possible via the use of your own language constructs). OOP is a natural fit for game objects, so most people will adopt that route.

OOP though, is more often than not, only used at a higher level within a game engine. The closer you get to the low level code, the more it evolves into C-style approaches. Typically you'll sort the data from the higher level objects into arrays, and then process them efficiently in batches without C++ features such as virtual funcs, etc. That's not to say they won't use classes though (which are always a win), but sorting objects and then processing arrays is normally more efficient.... i.e. The following:


class Foo
{
public:
bool someConditionIsTrue() const;
void doSomeStuff();
void doSomeDifferentStuff();

void func()
{
if(someConditionIsTrue())
{
doSomeStuff();
}
else
{
doSomeDifferentStuff();
}
}
};


Will, more often than not, be converted into a more structured approach like so:


class Foo
{
public:
bool someConditionIsTrue() const;
void doSomeStuff();
void doSomeDifferentStuff();
};

void func(std::vector<Foo*>& inputObjects)
{
std::vector<Foo*> someStuff;
std::vector<Foo*> someDifferentStuff;
for(size_t i=0;i<inputObjects.size();++i)
{
if(inputObjects->someConditionIsTrue())
someStuff.push_back(inputObjects);
else
someDifferentStuff.push_back(inputObjects);
}
for(size_t i=0;i<someStuff.size();++i)
{
someStuff->doSomeStuff();
}
for(size_t i=0;i<someDifferentStuff.size();++i)
{
someDifferentStuff->doSomeDifferentStuff();
}
}


You'll note that classes are still used, however the pre-sorting of data in that way usually makes it much easier to process the code efficiently on multi-core systems. So it's rare to find an engine that adopts an entirely OOP approach or structured approach. It's usually a mix of the two (and potentially functional/generic approaches too). There is no right or wrong way, just use whichever approach fits the problem best....

Share this post


Link to post
Share on other sites
I think ExcessNeo has a hard time imagining how a procedural program would be written because he has little experience with them. Procedural programming also uses user-defined data types (struct in C) and is not all that hard to keep clean and understandable.

Quote:
Thing's like that I don't see how I could have solved as simply using a plethora of functions which would be hard to understand

If you had never used objects, you wouldn't see how you could have solved it simply using a plethora of classes which would be hard to understand. You can write clean, elegant solutions in both paradigms, and you can write crap in both.

I don't personally like OOP. Objects are useful, and so are function calls and loops, but I don't orient my programming to a single tool. I mostly program in C++, and I use objects when I am modeling something that fits naturally in that shape (I can give it a good name and the interface makes sense). This is probably around 75% of my code. But my objects don't belong to complicated inheritance hierarchies: I use inheritance about as often as I would use function pointers in C (e.g., when I need polymorphic behavior).

The OP should probably gain some familiarity with objects, at least to be able to understand other people's code. Then he'll probably find himself using objects very frequently.

Share this post


Link to post
Share on other sites
Quote:
Original post by ExcessNeo
NPC's are inherited from a pure virtual class which defines the core functions (such as Draw, Update), they also have a specific function for interaction with the player which can be called through update. For example currently if the player stands close enough to a friendly NPC that is walking it will stop until the player has left the vicinity and then continue on it's way. If the player stands close enough to a hostile NPC it will leave it's path to chase after the player and if the player is far away enough it will return to it's path.

Thing's like that I don't see how I could have solved as simply using a plethora of functions which would be hard to understand, where is the ability to expand on something with a procedural program?


Trivial to do in C with OOP like so:

NPC.h

typedef void (*NPC_update_func)(NPC* _this, float dt);
typedef void (*NPC_interact_func)(NPC* _this, NPC* _otherNPC);
typedef void (*NPC_draw_func)(NPC* _this);

typedef struct
{
NPC_update_func update;
NPC_interact_func interact;
NPC_draw_func draw;
}
NPC_func_table;

typedef struct
{
NPC_func_table vtable;
Vector3 position;
Vector3 velocity;
Quat rotation;
int typeId; // 1 = villager, 2 = stormtrooper etc
} NPC;

#define drawNPC(npc) { assert(npc); assert((npc)->vtable.draw); (npc)->vtable.draw(npc); }

#define updateNPC(npc, dt) { assert(npc); assert((npc)->vtable.draw); (npc)->vtable.update((npc), dt); }

#define interactNPC(npc, other) { assert(npc); assert(other); assert((npc)->vtable.interact); (npc)->vtable.interact((npc), (other)); }

extern NPC* createVillager();
extern NPC* createStormTrooper();

// to prove it works for inheritance....
extern NPC* createVillageMayor();





villager extends NPC

typedef struct
{
NPC npc;

// villager specific params

} NPC_villager;

void Villager_update_func(NPC* _this, float dt)
{
NPC_villager* villager = (NPC_villager*)_this;

// update the villager
}
void Villager_interact_func(NPC* _this, NPC* _otherNPC)
{
NPC_villager* villager = (NPC_villager*)_this;

// handle interaction
}
void Villager_draw_func(NPC* _this)
{
NPC_villager* villager = (NPC_villager*)_this;

// draw the villager
}

NPC* createVillager()
{
NPC_villager* ptr = (NPC_villager*)malloc(sizeof(NPC_villager));
ptr->npc.vtable.update = Villager_update_func;
ptr->npc.vtable.interact = Villager_interact_func;
ptr->npc.vtable.draw = Villager_draw_func;

// init the other params...

return &ptr->npc;
}




stormtrooper extends NPC

typedef struct
{
NPC npc;

// stormtrooper specific params

} NPC_stormtrooper;


void Stormtrooper_update_func(NPC* _this, float dt)
{
NPC_stormtrooper* villager = (NPC_stormtrooper*)_this;

// update the stormtrooper
}
void Stormtrooper_interact_func(NPC* _this, NPC* _otherNPC)
{
NPC_stormtrooper* stormtrooper = (NPC_stormtrooper*)_this;

// handle interaction
}
void Stormtrooper_draw_func(NPC* _this)
{
NPC_stormtrooper* stormtrooper = (NPC_stormtrooper*)_this;

// draw the stormtrooper
}

NPC* createStormTrooper()
{
NPC_stormtrooper* ptr = (NPC_stormtrooper*)malloc(sizeof(NPC_stormtrooper));
ptr->npc.vtable.update = Stormtrooper_update_func;
ptr->npc.vtable.interact = Stormtrooper_interact_func;
ptr->npc.vtable.draw = Stormtrooper_draw_func;

// init the other params...

return &ptr->npc;
}




Village Mayor, extends villager

typedef struct
{
NPC_villager villager;

// villager specific params

} NPC_villageMayor;

void VillageMayor_update_func(NPC* _this, float dt)
{
// call update on base class....
Villager_update_func(_this, dt);

NPC_villageMayor* villager = (NPC_villageMayor*)_this;

// do Mayor specific stuff...
}
void VillageMayor_interact_func(NPC* _this, NPC* _otherNPC)
{
// call interact on base class....
Villager_interact_func(_this, _otherNPC);

NPC_villageMayor* villageMayor = (NPC_villageMayor*)_this;

// handle interaction
}
void VillageMayor_draw_func(NPC* _this)
{
// call draw on base class....
Villager_draw_func(_this);

NPC_villageMayor* villager = (NPC_villageMayor*)_this;

// draw the village mayor
}

NPC* createVillageMayor()
{
NPC_villageMayor* ptr = (NPC_villageMayor*)malloc(sizeof(NPC_villageMayor));
ptr->villager.npc.vtable.update = VillageMayor_update_func;
ptr->villager.npc.vtable.interact = VillageMayor_interact_func;
ptr->villager.npc.vtable.draw = VillageMayor_draw_func;

// init the other params...

return &ptr->villager.npc;
}




It's fair to say that you can implement almost all OOP language features in strict C. Whether or not it is a good idea to do so, is another matter entirely......

Share this post


Link to post
Share on other sites
Quote:
Original post by alvaro
I don't personally like OOP. Objects are useful, and so are function calls and loops, but I don't orient my programming to a single tool. I mostly program in C++, and I use objects when I am modeling something that fits naturally in that shape (I can give it a good name and the interface makes sense). This is probably around 75% of my code. But my objects don't belong to complicated inheritance hierarchies: I use inheritance about as often as I would use function pointers in C (e.g., when I need polymorphic behavior).


+1

Share this post


Link to post
Share on other sites
Quote:
Original post by RobTheBloke
Quote:
Original post by alvaro
I don't personally like OOP. Objects are useful, and so are function calls and loops, but I don't orient my programming to a single tool. I mostly program in C++, and I use objects when I am modeling something that fits naturally in that shape (I can give it a good name and the interface makes sense). This is probably around 75% of my code. But my objects don't belong to complicated inheritance hierarchies: I use inheritance about as often as I would use function pointers in C (e.g., when I need polymorphic behavior).


+1


+2

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!