Sign in to follow this  
Waaayoff

To OOP, or not to OOP?

Recommended Posts

Many people i talked to seem to HATE Object oriented programming. They say that OOP code takes more space than 'normal' code, is unnecessarily complicated and requires greater processing power and time to use/compile. I would really appreciate it if you could tell me why you chose to use/not to use OOP. Thanks :)

Share this post


Link to post
Share on other sites
Use OOP if it fits your problem (and thus simplifies your design and implementation). Don't try to fit absolutely everything in an OO framework just because you think "OO" implies "good".

Further reading: "Why C++ isn't just an object-oriented language" by Bjarne Stroustrup.

Share this post


Link to post
Share on other sites
It sometimes depends on the language though too. I found when I was doing a tetris clone in java one day, that using more OO made my life easier. However, doing a pong clone with SFML and C++, I had about half the code OO, the rest just procedural with some helper functions. The reusable object I had in Pong, was just a Piece class, that stored various float variables, and had getters/setters. X & Y position, height, width, etc. Other than that I just used helper methods to work with the SFML framework.

Share this post


Link to post
Share on other sites
Quote:
Original post by agm_ultimatex
The reusable object I had in Pong, was just a Piece class, that stored various float variables, and had getters/setters.

Many purists will argue that getters and setters are the antithesis of OO.

Share this post


Link to post
Share on other sites
Whether or not you should "use" OOP is a meaningless argument, devoid of context. Your goal in writing software is to write it in a readable, debuggable, testable, performant manner. You should use whatever techniques are appropriate for that. The important concepts for solid code apply whether you are writing OOP, imperative, or functional software.

That being said, saying broadly that "OOP code takes more space than 'normal' code, is unnecessarily complicated and requires greater processing power and time to use/compile" is flat-out wrong. While this is true of bad OOP code, there also exists good OOP code which is efficient, small, and readable.

Share this post


Link to post
Share on other sites
Quote:
Original post by DevFred
Quote:
Original post by agm_ultimatex
The reusable object I had in Pong, was just a Piece class, that stored various float variables, and had getters/setters.

Many purists will argue that getters and setters are the antithesis of OO.


Haha, hence why I said my Pong clone wasn't very OO. I suppose for what I did, one could almost use a struct. I did create a couple class methods that did some quick math, just to keep it somewhat DRY.

Share this post


Link to post
Share on other sites
OOP is not in the class keyword in itself. You can write object oriented code without it all together. The Win32 API is object oriented though it is written in C (though it's not necessarily the best designed framework).
An observation I have made in my own progression in projects and interleaved progression of such has been that:
1 - The end product can tend to be imperative especially when it's done over a short period of time.
2 - Refactoring causes code to be more object oriented.
3 - General purpose (or highly reusable code) is better suited to be object oriented.

It is in my preference to use "OO designed frameworks" (like DirectX) rather than "state machine designed frameworks" (like OpenGL) - as far as I have last checked, which has been for a while (OGL2 I believe)

My one and a half cent

Share this post


Link to post
Share on other sites
Quote:
Original post by DevFred
Quote:
Original post by agm_ultimatex
The reusable object I had in Pong, was just a Piece class, that stored various float variables, and had getters/setters.

Many purists will argue that getters and setters are the antithesis of OO.


Yes, in fact getters and setters are one of the enabling techniques of OO development (you can for example extend the getter/setter methods to read/write from/to a file/database/whatever without changing any code using the getter/setters at all!).

I think the "purists" are just saying that so that newbies don't immediately turn away from OO with the feeling "OOP is bullshit, I'll just keep using structs".

Share this post


Link to post
Share on other sites
Quote:
Original post by arithma
3 - General purpose (or highly reusable code) is better suited to be object oriented.

When I read "general purpose" and "highly reusable", I tend to think of templates, not OO.

Share this post


Link to post
Share on other sites
Its a matter of opinion. You cant provide any logical arguments for this at all. OOP and procedural both have a style to them and over time you learn which you prefer.

Just watch out for the "purists". These people are religiously driven to use their One True Paradigm and regard the other as inefficient, slow, confusing, complicated, simplistic or whatever else. Don't let those people make your decisions for you.

Share this post


Link to post
Share on other sites
Maybe I have a wrong idea of what OO is, but I gotta say I have a hard time imagining how you code games without using OO. Everything about a game's structure just screams OO, you have objects in the world and you manipulate them in some way, and whenever you are doing obj.do_stuff(arguments) or do_stuff(&obj, arguments) is just syntax to me.

Share this post


Link to post
Share on other sites
Quote:
Original post by marsong
Maybe I have a wrong idea of what OO is, but I gotta say I have a hard time imagining how you code games without using OO. Everything about a game's structure just screams OO, you have objects in the world and you manipulate them in some way, and whenever you are doing obj.do_stuff(arguments) or do_stuff(&obj, arguments) is just syntax to me.


If you have a hammer, everything looks like a nail [smile]. Tons of games, even modern ones, are written in pure C. Generally, an inability to conceive of a solution using another technique arises from not being fully familiar with that other technique.

This is a growing viewpoint though as it is now standard to do CS education in OO languages. It used to be the other way around: "I cannot possibly understand how you would construct a game using an OO language. Everything about it just screams serial functional programming"

-me

Share this post


Link to post
Share on other sites
Quote:
Original post by Waaayoff
Many people i talked to seem to HATE Object oriented programming. They say that OOP code takes more space than 'normal' code, is unnecessarily complicated and requires greater processing power and time to use/compile.
Quote:
Original post by George Carlin
Some people are fucking stupid!


You should talk to different people then.

Try Petzold's free e-book, Thinking in C++.

Share this post


Link to post
Share on other sites
Generally speaking OOP is less complicated, provided you use it right. It's meant to relate to the real world essentially. OOP is something we can relate to, as you use it to represent a real object or entity of some sort. Like in a board game, you have pieces, you have the board, the board has many spaces for pieces to go into, etc.

Share this post


Link to post
Share on other sites
Quote:
Original post by Palidine

If you have a hammer, everything looks like a nail [smile]. Tons of games, even modern ones, are written in pure C. Generally, an inability to conceive of a solution using another technique arises from not being fully familiar with that other technique.

This is a growing viewpoint though as it is now standard to do CS education in OO languages. It used to be the other way around: "I cannot possibly understand how you would construct a game using an OO language. Everything about it just screams serial functional programming"

-me


I've looked at some older game's source code, for example quake3, and to me that code is OO.
My understanding of OO is that it's a way of thinking, you group together some data, have some functions to manipulate them that are constrained to the object's invariants.
Then if you code in Java, C++, C or even Assembly doesn't matter.
But maybe that's the wrong idea?

Share this post


Link to post
Share on other sites
Quote:
Original post by marsong
My understanding of OO is that it's a way of thinking, you group together some data, have some functions to manipulate them that are constrained to the object's invariants.

What you describe is actually known as "object-based programming" or "programming with abstract data types". It is only when you throw inheritance and late binding into the pot that you arrive at "object-oriented programming".

See "Object Oriented Analysis and Design" by Grady Booch et. al. for a deeper analysis.

Share this post


Link to post
Share on other sites
Quote:
Original post by Konfusius
Quote:
Original post by DevFred
Quote:
Original post by agm_ultimatex
The reusable object I had in Pong, was just a Piece class, that stored various float variables, and had getters/setters.

Many purists will argue that getters and setters are the antithesis of OO.


Yes, in fact getters and setters are one of the enabling techniques of OO development (you can for example extend the getter/setter methods to read/write from/to a file/database/whatever without changing any code using the getter/setters at all!).


Just because you can do it that way doesn't make that way good, especially not in the general case.

The problem with "getters" and "setters" is that they're symptomatic of the fact that you aren't thinking about the object. You're thinking of individual properties of the object -- often treating them as outright separate. Worse yet, some people tout this as the epitome of OOP design, which absolutely is bullshit.

What would std::vector be like if it had .set_size() and .set_data_pointer()? Absolutely useless! It'd be impossible to hold one of the primary invariants that makes std::vector useful: It will always contain .size() elements.

We can argue std::vector has maybe a few getters: size() and capacity(). But is resize() a 'setter'? It doesn't just modify the size of the vector, it modifies the contents and possibly the memory allocated. Is push_back() a 'setter'? I don't think so. insert()? erase()? swap()? clear()? It's worth noting that all of these avoid the term 'set'.

This isn't to say an interface consisting of getters and setters is never useful as some sort of proxy to a remote database or the like -- but it is to say that it's most certainly not the one true path to OOP enlightenment (tm). And this is exactly what people are referring to when they talk of getters and setters being the antithesis of OOP.

And sometimes? A struct is entirely appropriate and all you need.

Share this post


Link to post
Share on other sites
I certainly agree that C and similar languages have their places, but I have some OO code that I would like to see done in C (good friggin' luck). Frankly, there are some situations that are just better implemented in an OO-manner. The same applies to procedural code.

Share this post


Link to post
Share on other sites
Quote:
Original post by Konfusius
Yes, in fact getters and setters are one of the enabling techniques of OO development (you can for example extend the getter/setter methods to read/write from/to a file/database/whatever without changing any code using the getter/setters at all!)



real_t vec3::getX()
{
// we need to download our X coordinate from the database
// when we need to access it
return fetchFromDatabase(this, VEC3_X);
}


We're not talking about non-trivial getters/setters.

Share this post


Link to post
Share on other sites
Getter/Setter insulation is the Java Tutorial BS - in past 10 years I've never heard of a case where they would save any meaningful time. I have however seen several enterprise grade projects with 100kLOC+ auto-generated code with nothing but getters and setters - whole libraries of nothing but classes holding variables - and unit tests testing them.

As a matter of fact, I've never encountered a getter/setter case that was not imposed by some ORM database mapping.

If G/S exists for sake of insulation the interface is broken already, and refactoring will need to be done. There is never, in real code, a feature request or design change that G/S would absorb.

G/S came to be after Java did away with what Delphi already did really well - properties. Delphi also exposed why "smart" G/S concept is bad. Entire VCL was built on this idiom:
void Widget::setSize(int newSize) {
if (size != newSize) {
size = newSize;
doSomethingFancy(size);
}
}
This lead to endless bugs where a new object was created but the setSize was called with same value as deep-hidden default, causing a cascading - nothing. Entire event chain failed, and application was broken, yet running perfectly.


It's about design: Don't ask - tell

Procedural OO (CRUD ORM, get/set based apps) results in this:
getFoo().getBaz().getBar().x += 17;


Better:
XAffector xa(17);
BarPolicy ba(xa);
foo.apply(baz, ba);


Even if in this case it seems that latter case is coupled closer and more confusing, practice shows it's not. There is only one level of coupling (xa+ba and foo+baz+ba).

And once you have that, you might as well move everything into implementation detail:
Foo::apply(Baz baz, int x) {
XAffector xa(17);
BarPolicy ba(xa);
// directly apply ba to baz
};


Getters and setters are hollow and don't express anything. They are just accessors.

OO is about expressing function, role and intent. G/S don't do anything about it.

---

The above applies to exposing variables or single values via G/S. Compare this to vector:
int vector::getSize(); // getter
void resize(int newSize); // not setter -+
void clear(); // not setter -+-- function/role/intent (or whatchawannacallit
iterator end(); // not setter -+
All of these are interconnected in non-trivial way, but they are all about encapsulating some complex internal state.

With G/S pairs, this logic is moved elsewhere. Consider:
void myResize() {
int oldSize = vec.getSize();
int oldCap = vec.getCapacity();
if (oldSize+1 >= oldCap) {
vec.setSize(oldSize*2);
vec.setDataPointer(allocateHelper(oldSize*2);
vec.setCapacity(oldSize*2);
}
};

Once this happens, changing G/S becomes impossible. It might make sense to change setSize() and setCapacity() so that they allocate new memory itself - guess what happens with above code. Now imagine that such setters are referenced thousands of times.

Interfaces are incredibly expensive to change. So keep them minimal and expressive about domain they encapsulate - not the variables.

"Getters" and "Setters" must encapsulate the invariants of the problem domain they are implementing. That is a very different thing from getFoo()/setFoo() - in languages with properties that is a problem solved by compiler.


PS: rantish....

Share this post


Link to post
Share on other sites
In my game, there were a couple times when getters allowed me to avoid rewriting some code while making changes to the class. However, the savings were relatively trivial compared to the frequency with which I was rewriting the interface anyway, and the time spent making the accessors in the first place.

At least I mostly only use accessors in places where they are nontrivial or I expect to change them later.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this