So OOP is crap?

A lot of things that are listed here as disadvantages of OOP don't really have anything to do with OOP. You can do OOP in plain C or even in assembler, you don't need any fancy programming language features like classes for that. But the opposite is also true - you can use classes and not really do OOP.

A lot of things that are listed here as downsides of OOP are not good OOP practice either. Take for example Inheritance. Warden wrote "Inheritence is a poor model for reuse". That is true, but OOP doesn't force you to do this - Composition over inheritance is a common principle in OOP.

Also the performance issues are more or less a myth. Yes, virtual dispatch is slower than regular function calls, but sometimes you can't get around doing that. IIRC Casey hinted at doing this with function pointers. And quite often it just doesn't matter. Take a look at all the applications with great performance being written in scripting languages or even byte code languages like C# or Java. Even parts of games use that - game logic for Unity 3D games is written in C# or even JavaScript. And lots of other games embed scripting languages with no performance problems because of that. And I think we all will agree that virtual dispatch is magnitudes faster than interpreting code.

For some problems objects are just the natural solution - you will find them in all kinds of code, plain C-code, pure functional code and yes, even in Handmade Hero.
Minor nitpick - Unity uses UnityScript, not JavaScript. It's based on JS syntax, but it has differences. And it is not scripting language as in "interpreted from source" sense. It is compiled to .NET bytecode. And that (same as C#) is JIT'ed or AOT compiled depending on platform.
I'm going to have to disagree with you 5sw on performance issues being a myth on this one.

Tony Albrecht explains far better than I how you can get pretty massive perf gains by organizing your data carefully and not carelessly doing things the "OOP" way: http://research.scee.net/files/pr..._Oriented_Programming_GCAP_09.pdf
Just my two cents: what's good about OOP is coding to interfaces. New programming languages seem to get this, as that is the way new (relatively) low-level languages like Go and Rust do it: data types can implement interfaces, but there's no inheritance.
OOP does have nothing to do with how the data is actually laid out in memory. Yes, it will take more work to do it well, but that's always the case. Even if not doing OOP one can do a crappy memory layout that will be slow.

Also, see slide 109 of the linked presentation: "OO is not necessarily EVIL".

And still, there are lots of places (even in games) where it just doesn't matter how fast or slow code is.

Edited by Sven on
5sw
A lot of things that are listed here as disadvantages of OOP don't really have anything to do with OOP.


Depending on definitions, maybe... maybe. I guess my comments were in relation to "real OOP as practiced and evangelized in the wild, and encouraged through the most widely used OOP languages: C++, Java, and C#." And I should further qualify that some of these things are only problems in certain domains.


5sw
Take a look at all the applications with great performance being written in scripting languages or even byte code languages like C# or Java.


We are clearly not using the same definition of "great" performance.


5sw
For some problems objects are just the natural solution [/quote ]

agreed.


5sw
you will find them in all kinds of code, plain C-code, pure functional code and yes, even in Handmade Hero.


We shall see whether we end up with object-shaped things in HH. I thought this for a while, but people smarter than me, including Casey, have indicated that this is not likely to be the case.

I'm sorry you found my comments so disagreeable. I am not a dogmatist, and I am simply relating some truths which have been shown to me and which are helping me to become less of a dogmatist.
@5sw,

OOP is really about the following things:
  • encapsulation
  • extensibility via inheritance

Both of these can have significant impacts on your performance.

Here's a way to think about it, using a Vector2f as an example.

The "object" approach":

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Vector2f {
private:
    float x;
    float y;

public:
    float get_x() const { return this->x; }
    float get_y() const { return this->y; }
    void set_x(float nx) { this->x = nx; }
    void set_y(float ny) { this->y = ny; }

    virtual float length() const { ... }
};


The "non-object" approach:

1
2
3
4
typedef struct {
  float x;
  float y;
} Vector2f;


Here's the thing, as a consumer of the Vector2f type, you have no guarantees of what the memory layout of the type is going to be; that's a key tenant about OO. The logic around that is encapsulated from you. I could go add a few other properties at a later time to cache values like the dot product, normal values, etc... and add that to the class and you won't know that.

For high-performance code, this is a really bad thing, especially if you are using a library that is providing these types because they can and do change over time. You can literally go from build to build of your product with different performance characteristics just because someone is mucking with the "private" portion of the Vector2f class.
what... this is just silly. You would never write a Vector2f like that, and waht does a virtual function have anything to do with anything there? First of al it's just weird, and secondly, you have not provided any similar functionality in the none OO version.

That OO implementation is just pure stupid IMO, and I bet no sane programmer would implement a vectors component as private. That's just silly. Also, you would definitely have all those function inlined as well.

Like I said in my post before, OO is no reason to not understand everything that is happening underneath. If you want to make a good program, you need to understand everything that is happening. EX: adding virtual function will make the object take up more memory.

OO is very useful, but you have to use it right. Also, like with most code, if someone else is manipulating it without your knowledge, and changing things under the surface, you can no longer be sure that it’s running optimal. It has nothing to do with OO.

IF you want to prove anything, please proved a better example.

PS: About C# and unity... and anything C# related... it's almost impossible to write really good game code in C#, as it's garbage collected. Even if you pool all memory and try to avoid run time allocations as much as you can, it's almost impossible to avoid in C#, especially if you use any third party library at all.

Garbage collection will result in spikes... and that is awful.

Sorry if I sound harsh... I just don't have that much time, and I'm tired on people blaming OO.

Edited by Gafgar (Anders Davallius) on
You're right, I wouldn't write a vector like that. But when you are taught OO, to "model the object".

So people end up with designs that have things inheriting from base classes for functionality when it's simply not necessary.

1
2
class Vector2f { ... };
class Vector3f : public Vector2f { ... };


If you've not run into code like this, then count yourself lucky. I see this all the time from people that have only been taught OO and then try to solve real problems with.

People make the length() function virtual so that it can overridden in their inheritance chain.
owensd
You're right, I wouldn't write a vector like that. But when you are taught OO, to "model the object".

So people end up with designs that have things inheriting from base classes for functionality when it's simply not necessary.

1
2
class Vector2f { ... };
class Vector3f : public Vector2f { ... };



I honestly have not seen such a thing so far. And something like that would end to some longer talk ...
Strawmen aside, OOP is about two things, as has been mentioned above:

1. Encapsulation
2. Polymorphism

Encapsulation means you don't get to know the internal representation. If you have to know that anyway, encapsulation only gets in the way. If the counter argument is "don't encapsulate", then we are in agreement. OO isn't helpful here.

Polymorphism means treating heterogenous things (whose internal representations I can't know) homogenously. Heterogenous things don't pack in memory well without some coaxing, so less experienced programmers will gravitate toward a linked list or similar structure.

It only seems to get in the way and make what we are trying to do here harder. What am I missing?
If I may, I think part of the problem here is that different people like to define OOP in different ways, and it's not always clear what they mean by OOP. I define OOP as exactly what its name implies: that the practice of programming that you employ starts with the objects and is oriented around them. That is strictly a bad programming practice, and I have literally never seen anyone use it effectively. Ever. Not even once.

If by "OOP" people mean something very minimal, like "there is a struct somewhere in my system that is not exposed to the rest of the program that also has some functions that mostly just operate on it and not other things", that was something that existed long before anyone ever used the term "OOP" and is clearly not object oriented programming, it's just regular programming :)

People saying that OOP is a good idea who don't mean one of those two things should first say exactly what they mean by OOP so that people can first see whether they agree or disagree that the practices to which they refer are good or bad without arguing first :)

On the Wikipedia page, for example, there are a number of statements which reinforce this notion that people saying "object oriented programming" really aren't saying anything at all, because the term has so many different meanings depending on what you're talking about. To quote, "Benjamin C. Pierce and some other researchers view any attempt to distill OOP to a minimal set of features as futile" and "a significantly different yet analogous terminology is used to define the concepts of object and instance" and "John C. Mitchell identifies four main features: dynamic dispatch, abstraction, subtype polymorphism, and inheritance.[21] Michael Lee Scott in Programming Language Pragmatics considers only encapsulation, inheritance, and dynamic dispatch." Etc., etc.

Personally, I think it's all nonsense and the concept that you would think of "programming techniques that go together" as something that is important is a bad way to program. For example, even if inheritance was a good idea, the concept that you would bundle it together with other things and say "this is a programming paradigm we call object-oriented programming" is a classic example of how not to program. The techniques are just all the things that the language happens to allow, and the programming practice should be compression-oriented and built around starting from the direct implementation of what the CPU needs to do then abstracted upward into reusable parts. The techniques used to do that abstraction should be whatever the most compressible version is supplied by the language, period.

- Casey
Speaking of programming paradigms, I read an article bashing "compression oriented programming". Basicall is says, it's an anti-pattern, uh, except when it's not. I wonder if Casey's read it? I understand his sentiments on the issue, but I think he missed the point of what Casey means by "Semantic Compression".
http://mikedrivendevelopment.blog...mpression-driven-development.html
I was thinking also, about the minimalistic use of OOP, but I always thought that was just called class-based programming. Hmmm, semantics.
Yeah... I suspect the entire point was missed there. I can somewhat see that blog post's point of view from what I knew to be "good programming" right out of school, but even still.

The more and more I program, the more I've come to appreciate that it's just way easier to program when you try to understand what the CPU actually needs to do and write the most direct code necessary to get the CPU to do that thing in whatever language you use, as Casey mentioned.

If you notice some similarities in different areas of the code and can "compress" without adding obtuse abstractions then you can get something nice to reuse. I consider this more of a "bottom up" point of view.

The way I was taught to program was a very typical high-level, theoretical CS point of view which is start at some abstract notion of what you want and just write code that mirrors that and eventually some compiler people will get you down to the CPU so it actually runs. This I view as the "top down" way of programming.

I've been hamstrung by an incredible amount because of this sort of indoctrination. It's just so harmful when you want to be an effective programmer in the real world. The code is a mess and becomes almost impossible to reason about the costs of anything regarding it.
I think I lost a few IQ points just opening that blog post :( You can lead a horse to water, but you can't make it drink, I guess!

- Casey