Sunday, August 26, 2012

Does Object-Oriented Programming really suck?

I recently read Armstrong essay on how much OOP sucks. While such opinions would probably have considered pure blasphemy a few years ago, nowadays they are becoming more popular. So, what’s the matter with OOP?

The first thing that comes to mind is that OOP promised too much. As already occurred to other paradigms and ideas (e.g., Logic Programming and Artificial Intelligence) sometimes researchers promise too much and then they (or the industry) cannot stay true to their promises.

OOP promised better modularity, better code-reuse [0], better “whatever”. Problem is, bad developers write crap with every single programming paradigm out there. With crap I really mean “utter crap”. A good programmer using structured programming and a bad programmer using OOP, is that the good programmer’s structured program would probably look “more object oriented” than the other one.

Another problem occurred in the OOP community: OOP “done right” was about message-passing. Information Hiding, Encapsulation and the other buzz-words are a consequence of the approach (because object communicate with messages, their internal state is opaque) not a goal of OOP. Objects are naturally “dynamic” and the way we reason about code is separating concerns in objects having related concerns and having the objects communicate in order to achieve the task at hand. And I’m a bit afraid of talking about “OOP done right”: I really just have my vision. OOP is very under-specified, so that it becomes very hard to criticize (or defend) the approach.

However, OOP becomes “data + functions”. To me data is simply *not* part of OOP. It’s an implementation detail of how objects maintain state. As a consequence, I do not really see data-driven applications as good candidates to OOP. Once again, OOP was sold as universal. It is not. Consider the successes that functional programming is achieving (performance and concept-wise) in this area.

This “data + functions” comes from C++ being the first commercially successful OOP platform. The great advantage was that the transition from structured programming to OOP was quite more easier, that programs could be far more efficient (read “less runtime”) than message passing dynamic OOP systems, at least back in the day. However, there was so much missing from the original idea!

Since back then classes were considered good (and C++ had — and has — no separate concept of interface) + static typing and a relatively verbose language with no introspection, it became rather natural to focus on inheritance. Which later was proved to be a bad strategy. Consequently, there is less experience in building OO software than one would think, considering that for a large part of its history OOP was dominated by sub-optimal practices.

So, what is really bad with OOP? Following Armstrong:

Data structure and functions should not be bound together

Agreed! But I believe that Data Structures are not *truly* part of OOP. Let me explain.

Data is laid out in some way. There is a “physical layout”, for example. You can express that very precisely in C with extensions, to the point of exactly specifying the offsets of the various datas. A phyisical layout also exists in high level languages such as Python. However, it is not part of the Python model. Of course with the struct module or ctypes you can fiddle with it (but they are libraries), however, for the most part, it is just outside the conceptual language used to describe the problem.

Data is also laid out in logical ways. Computer Science defined many data structures and algorithms over them. You can use OOP to express such structures and such algorithms. Still they are not “part” of OOP, they are just expressed in an object oriented way (or maybe not, and remain at structured programming level).

One very good practice in OOP is not using together in the same body of code objects reasoning at different levels. So, for example, you have your low level business logic code that is expressed in terms of data structures, high level business logic expressed in terms of low level business code… and that’s it. Functions is not really together with data. You don’t have “data”. You have some layers of objects.

The point is that OOP is about creating languages at semantic level (you usually do not get to change the syntax). That’s it. If the language is good, well… good. If the language is bad, ok, we’ve got a problem.

Is this suboptimal? In a way, yes. All the indirection may be very expensive. And since abstractions, well… abstract, you may find yourself with a language that is not expressive enough (at least not at the expenses of additional performance costs). Still functions and data structure is not bound together. You just have objects and messages. No “functions” and no “data”. Please notice: this may not be the right thing to do. Still, the problem is not with data + functions, is just related to applying OOP to a specific domain that is ill suited for the approach. OOP is not for every task in the world. But the same objections applies to every system that is built as a stack of layered abstractions.

Please also consider the Qc Na story! Objects are not necessarily opposed to functional programming (you can see them as closures that make different actions available). Objects are just about state + behavior + identity.

Everything has to be an object

And this is something that I don’t think is a problem. It is like saying that Scheme is bad because “everything is a list” (which, strictly speaking, is not true, there are atoms and lambdas etc). If you do not want to program OO, then don’t. If you want, you probably want that everything is an object.

The only issue with everything is an object is, sometimes, performance. From a variety of points of view, such strategy may kill performance. Objects usually have indirections (read pointer). 64 bit pointer for every integer is bad. So we have hybrid stuff like Java and then we have to deal with boxing (either manually in the past or automatically right now). Performance issues can be somewhat “fixed” using proper JIT systems or other optimization techniques. Or providing libraries that do the right thing (see Numpy, for example).

Other than that, I prefer objections in the line of “this thing that should be an object is something else” than those requesting that something that is an object really is. So, I can favorably consider an objection that says that, in Python, “if” is not an object (true). Even though I’m convinced that having if as a statement is not bad either.

And the whole objections with “time”… well, time (and dates) are a bitch to handle. But I find that Python datetime module gets as close to perfection as humanely possible. I really can’t see describing time with a bunch of enums + some structures as an improvement. On the other hand, it looks to me as one of the cases where it is *easy* to see that the OO approach works better.

Consider the related problem of representing a date in a locale. If you introduce a new representation of time, you need either to modify the original function or create a new function (maybe one that works with both things). Creating an interface, on the other hand makes it very easy to introduce new representations of time.

Objection 3 - In an OOPL data type definitions are spread out all over the place


And once again, in OOPL languages data type definitions are not spread out all over the place. They are in C++ and perhaps in Java. And even in Java, if things are done properly, you reason in terms of interface, i.e., in terms of typed messages, not in terms of data structure.
“”“In an OOPL I have to choose some base object in which I will define the ubiquitous data structure, all other objects that want to use this data structure must inherit this object. Suppose now I want to create some “time” object, where does this belong and in which object…
””“
Here it is pretty clear what he has in mind. I think that it is clear that, conceptually, time is an interface and that there is really no need for it to define “data structure”. And if your language is duck typed, the interface is implicit and you have finished before you started.

Objection 4 - Objects have private state


And here I have to agree: state is the root of all evil. Problem is that entirely stateless systems are simply unpractical. We reason in terms of state. We can describe lots of things as stateless, but somewhat we have state. We have files. We have documents. We want them saved and retrieved.
So, we have to deal with state. Agreed. But: 1. imperative programming is about state2. object oriented programming is not, strictly speaking
You can use a “functional” style in OOP, for example. Most of the times, you don’t do it because the code becomes harder to write. But in many situations, on the contrary, you do it because it makes it easier. Often I write immutable objects that cannot be modified: they are not more stateful than a parameter in a function.
Sometimes this is not practical. Ok. And surely using a very stateful style of programming is bad. State in OOP is expressed as behavior. That’s it. Sometimes is done properly, sometimes it is not. Some strategy to deal with state are extremely nice (STM, as an example). Others are not. Also consider how “modern” functional languages really merge concepts from OOP (without being OOP) and how “modern” OOP languages merge concepts from FP (without being functional).
Examples: Python from the OOP side, using generators, lazy evaluation, list comprehensions, closures, etc etc etc.Clojure from the FP side… and all the features it has to express what resembles interfaces, STM and so on…

——

[0] someone once told me they feel lucky when they can actually use the code effectively once, let alone reusing it.

9 comments:

Anonymous said...

You have touched on the age old question about languages and keeping you [the programmer] safe. When I was at DEC (Digital Equipment Corp) Version 2 of VMS was written structured `a la the top down/Pascal thinking of the day. It was so slow, that Version 3 came out in record time, and went back the traditional ways of writing OSs.

When C++ came out in the 90s, people training us, formally in schools like Harvard Extension (instructors were from Object Design in Burlington, MA) and in house training folks all warned about jumping onto C++ blindly and without thought. But, as you have stated, people wrote a lot of bad code. Even Microsoft's MFC boilerplate classes kept state in public variables and tweaked that state instead of going through get/set member functions.

Java's early touting was it was going to protect the programmer from those nasty pointers. Now, everyone seems to be bashing Java.

Additionally, along with Java bashing we seem to be on the functional craze.

I'm learning Clojure, but it is less about it's better than what came before and more about doing something different and getting my mind to see problems differently. So far, the effort has been well worth it.

Thanks for posting this.

Unknown said...

Yes, back then it was a real mess. Besides, my idea is that Java simply promised more than it could really give.

I agree that some ideas were pretty good, problem is Java was already old when it was created (compare with similarly old Python, or Ruby, that is just 3 years junior).

So while Java solved many issues C++ had (pointer related bugs, lack of interfaces, etc.) its designers decided to keep its features at the bare minimum. However, the advertisement (and the evangelists take) was that Java was a "modern" and "productive" language.

If they simply said "C++ for business stuff has too many issues, and Cobol is worse, Java does it right, nobody would be complaining.

Problem is, when they say that Java is "productive" if you worked with Ruby for like two months you know it is not true. And then the bashing. It's' just a matter of being unable to be true to one's word, in my opinion.

Functional programming is great. But I agree: its a craze. We know better than believing that 'the next language is a silver bullet'. There is a whole class of problems that are very suitable for a functional approach (performance-, readability- and maintainability-wise).

Big data roughly falls in this category. Auto-vectorization and the like are really great to have, same applies for stateless programming (state means memory, while if you can really use a pure streaming approach you don't use that much memory [0])

Stuff like web-servers (or servers in general) are another surprising example of things that functional programming can really solve well, especially if you can express state cleanly.

But functional programming is not optimal for everything. In some years maybe we will see functional programming becoming dominant (for some reasons I don't think it will, too much money has been spent on OOP and functional guys usually are not very enterprise friendly) . If it does after like a decades a new paradigm will come out that will perform better than FP in the areas where FP is weak. That's about it. Maybe such paradigm has already been created, still we do not think it is good.

FP is old as CS itself, afterall. OOP in fact was theorized in the seventies and some work even predates that (Hoare's for example).

----
[0] unless it is one of those problems that has very natural imperative state-mutating solutions and there are no copy-less alternatives.

Unknown said...

Since when C++ lost intefaces AKA abstract classes? With all respect it's never been a problem for the languages. Pointers - may be, but exagerated otherwise.

Unknown said...

Abstract Classes are not interfaces. Interfaces are abstract types, though. Stricly speaking, abstract classes are less restrictive than interfaces, since they allow to give partial specification of stuff.

Besides, my original claim is that C++ has no separate concept of interface, which is hard to prove wrong. Abstract classes and regular classes are just semantically the same thing (and work in the same inheritance tree): the only difference is that abstract classes are allowed to leave unspecified stuff.

You can have abstract classes inherit from non abstract classes, for example, and vice versa. As a consequence, C++ has no *separate* concept of interface, because it uses the same concept (class, although abstract) to implement the idea.

So while it is incorrect to state that C++ has no concept of interface (because you can implement interfaces with abstract classes), it is also incorrect to say that C++ separates the concept of interface from that of class.

Moreover, I firmly believe that interfaces are somewhat closer to the idea of OOP as "message passing stuff" to that of "data + functions" that I dislike, while abstract classes are, once again, data + functions.

I'm not into the crappy static type systems OOP languages have, but if I just have to choose I rather prefer the separation of interfaces from types, because it makes the distinction between class and type (see the initial pages of the GOF) somewhat more evident.

Yes, I also miss the concept of mixin in Java, while it is very easy to implement in C++. So really, sometimes mixins or abstract classes are *very* useful, but that does not make them the same thing than interfaces.

Anonymous said...

The OOP does not give any advantage over the procedural programming. Methods are still functions taking a hidden this parameter, virtual functions are just function pointers in a hidden struct, what else OOP can do?

I see no advantage here. No paradigm is better than others because the programs written in it still running on a computer and by the same CPU.

One cannot simply abstract the computer away. Regardless what paradigm you use, if you want to write fast programs in it, you must look under the hood, and find out how it work.

OOP only had good marketing, that's why it's so popular.

Unknown said...

@calamarius. Agreed on the general sense. However, I think that syntax matters. Really.

Nice language features with ugly or unpractical or verbose syntax are seldom used. Sometimes they are "rediscovered" when a newer language packages the whole thing with a more practical syntax.

As a consequence, although it is true that most features of OOP you can have in procedural languages, it is also true that you have to:
1. basically write the runtime support for it
2. use a more verbose and potentially confusing syntax, unless your language is very strong on the 'meta' side.

So, if you are using scheme or lisp, yes a practical object system can be easily written. They are not "procedural", however.

If you are using C or plain Pascal, on the other hand, maintaining an OO structure on your own is not exactly trivial.

In fact, most issues with low level OOP languages are present also in languages such as C or Pascal. On the other hand, you lose some of the nice not-necessarily-oop features that have been added.

Besides, the 'OOP' as function pointers + data is exactly the kind of OOP that does not bring great advantages over procedural.

If you start reasoning in terms of interfaces and message passing, things become even messier and more verbose if your language does not support it.

For example, Objective-C supports all the 'nice' message-passing related things of OOP. And, in fact, sometimes is implemented as a pre-processor to regular C (nowadays, gcc does not follow this approach, though).

And there are features to 'call' Objective-C from regular C. Which are far less readable than plain Objective-C.

I'm not a huge fan of OOP, in fact. However, I would not deny the fact that 'OOP done right' is a step forward with respect to procedural programming.

High level functional programming may (or may not) a big improvement over both. Depends on what you have to do...

moronicmisfit said...


OOP sucks, want prove? Go program something in Purebasic (Procedural), lets say Custom Printing Function that changes the color of each character it prints.

Then call it with lets say PrintColor("OOP SUCKS ASS",pcx,pcy)

Do the same with lets say AS3, the simplest of OOP languages.

And after you encase your code in Brackets, and extend it from some other class, lets say :Sprites, then you create a contructor with the same name as the class, so you can then enter some god damn code.

Then you set up your other functions right after the constructor...,

Fancy way of calling a Procedure dont ya think?

You might not get a class error. but you better have a good OOP book next to you so open it, just incase you do get one,

I'll out code any of you in Purebasic. with any kind of program anytime you want.

Hell if Purebasic worked right from a browser I'd never touch another freakin OOP language again.

And thats in where the popularity of OOP lies, with the net. every freakin languages thinks it must have OOP to be on the net, what a joke!!!

Oh and that it's tools are free, go check out flashdevelop by the way if you are stuck OOPing. its free and good, how rare is that?

I know your type,... you OOP defenders.... never programmed anything yourself, you just cut and paste code from other sources and call it your own.

Thats sad and a hell of a way to program.

Just about everything I have ever written, was from my own mind, and finger tips. I dont steal code from others and I dont defend a poor idea, Like OOP.

And please dont use the reusable code idea to defend OOP, thats a freakin lie!!.

YOU call a procedure! thats it,

You dont have to make a freakin copy of it like you do Classes. You dont have to create and destroy Objects in Purebasic or any other procedural language. you just call the function that does the work.

And any of you reading this tryin to decide if I'm right. Go out and try both ways,

Purebasic (procedural) demo is free as well as flashdevelop (OOP)!!

Code a multi-colored Print statement in Pure, then do it with flashdevelop and AS3. bet you Purebasic one took you alot less time.

In the real world, workin code matters, not theory, and thats all OOP is, its theory code.

Horrible looking, Syntaxtically locked,(yes my word), overtly complicated, and just a pain in the ass to make anything functional! in OOP at all.

You can argue all you want, the sad truth is this, the industry convinced some of you that OOP was the better than sliced bread through a gooses ass, and you all fell for it.

Almost killing procedural languages in the process. Look I dont care what the hell you program in, But I do care if my Procedural languages will be around for others to enjoy.

SO dont believe the Hype. OOP sucks, always has, it never full filled its promise of a better programming world, if anything, it took the easy out of programming, and maybe that what these "O"heads want. less people programming so they have less people to compete with.

You'll spend more time trying to figure out how to program properly in any OOP language than you will getting your program actually written. the proof is in the coding. if you are man or woman enough, try it, use both, I'll return to see your code printed up here, you have been challenged, prove me wrong!!.

But I bet you'll just find I am right and OOP does suck. and Procedures are fun, just plain fun to work with.

And there is no code that cant be done with procedures, and if any OOPhead tells you different, he's just lying to cover his stupidity up.

Oh and lastly, it being called OOP cracks me up, cause to me, it is a big OOPs, the worst kind, it makes people believe in a lie,

How sad it that, true believers!!

NUFF SAID!!!!!!!!!!!!!!!

The Last Ninja said...

Coming from a background as an assembler coder during the 80's and 90's I can say that OOP is sometimes very useful and other times not practical. Not everything is an object nor should be.

For instance, I used to program arcade games. Code to handle the video would be procedural functions working directly with the video hardware. It would make no sense to make the video card an object because there is only one of these that would be controlled by physical registered at set locations.

When programming the game logic, sprites or actors would be objects because they are more conceptual and they could be a number of these being represented at one time while having slightly different behaviors.

Programming language build around the idea that everything has to be an object are just plain stupid.

Jbc said...

OOP sucks ass, it's the cancer in programing, a spreaded lie by typical "IHaveAMasterSoIKnowAll" dude that ate all bull shit from any java programming course..

Just by experience anybody supporting/programing aplications in both kind of languages can tell you estructured is far easier to understand, code and support one you want to do something bigger than my grandma shoe shop application.

Those freaking gigantic broccoli-like schemas made of 666*10^N classes where N is the version number is what I have to deal and try to fix every day...

This shit leads to having to reboot appservers each week (if we are lucky) because of some mystery memory leak that NO ONE in the world will ever find because its all OOP java/.net made and takes one month just to find out wtf the program does with the memory when you do one click.

So please, dear garbage collector class, clean all this shit and the ones deffending it, those who I want to be brain surgeon operated by a oop guided surgeon robot.