The GoF book did a lot of damage. I've finally read it and was amazed that the entire book is in fact about writing GUIs, which is just one tiny part of programming.
Several patterns are trivial, others are very similar and are just a linked list of objects that are searched for performing some action.
The composition over inheritance meme in the book does not make things easier (there is no "composition" going on anyway, it is just delegation).
Objects themselves for resource cleanup like RAII are fine of course.
I feel very lucky (in many ways) that I started with VB5 and Turbo C/Pascal. Sure, you can do OOP in VB6 but the books I read did not touch this area.
Then I tried Java. I hated it! This would have been around 1998.
The Java books I was reading were huge and half of it was not entirely about Java the language.. but OOP concepts. Some of it was inheritence hell! I remember looking at code that was just a bloat.. when in C it could be a couple of structs and 10 functions.
Then "Design Patterns" was thrown around in Job adverts. I had to bite the bullet and learn it to get my foot in the door. I was 18 at the time.
Once I got my foot in the door and gained the experience needed to get good as a developer, you soon get a handle of what works and what doesn't. Am I suggesting OOP is bad? No.. it has its place. I found the GoF is not as serious as it is pushed.
It was not long before I went full circle, coding more away from typical OOP mindset. I felt like the odd one out when I tried to explain this to co-workers but once we reached 2010's with the coined "Data Oriented Design" I realised my mindset is shared by many.
Personally -- and.. yes.. this is controversial.. I think OOP set us back 10 years of programming progress. Not because of OOP itself, but how large companies jumped on the bandwagon and encouraged developers that "this is the right direection" so much effort was there, creating large.. bloated.. monolothic code.
I felt like Dlang was an interesting step forward but, sadly, it is a language that tries to be everything. Now with Rust, Zig and Odin, I do believe that OOP will slowly lose in popularity but it will be a very, very slow decline.
These so-called 'patterns' are just language features in many languages, which makes it sad I had to learn them in university. Optional/default parameters, higher order functions, closures, ... The 'patterns' only make sense in Java because the language itself is so limited.
I’m so glad to hear others putting words to my own thoughts. I haven’t read all of Design Patterns because it kept striking me as wholly unnecessary in the languages (mainly Python) I was using at the time. I mean, if you want to put name on every kind of chunk of code you can write, go for it. I’m not going to argue about whether calling a function on each item of a list is better or worse than passing that list to the function based on which one is a documented pattern, or debate which pattern to use to make an HTTP GET request. I’d much rather just write the things.
I’m sure lots of people got value from the book. I pity that they were in a situation where it was useful.
> The 'patterns' only make sense in Java because the language itself is so limited.
I will always remember the first pattern I learned -- the Decorator Pattern.
From memory, the example used was making hot beverage.. adding milk, sugar, etc. I looked at the code and said "So its a Link List of items?"
I understand the book was covering things in a simple manner but even this looked like bloat, with things like Milk, Sugar, etc.. being its own class (inheriting the decorator) that, in the end, is simply a enum with a couple of structs if using a language like C.
I just felt it we are adding +30 lines of code for this SIMPLE example -- how much bloat would it be for real world solutions?
Agreed, OOP became 10 times worse after the GoF book. People started to see these patterns everywhere, and mutated fine looking code to conform to that expectation. Just compare Java classes and interfaces when the language was created (most of that based on previous experience with Smalltalk) and the hot mess that was invented after GoF was released.
OOP is entirely about writing GUIs. (Well, the C++ idea of OOP.)
It's a much larger part of programing than most people give credit, but yeah, it's only a part.
Anyway, the GoF book is about getting good abstractions from the 90s limitations in OOP languages. Nobody should read them now, except for historical reference.
C++ was originally designed as Bjarne Stroustrup was in the process to create distributed applications in UNIX at Bell Labs, and after his downgrade experience from Simula to BCPL he wasn't touching raw C for such purpose, thus C with Classes was born.
Not disagreeing with your comment, but IMO this is just another historical accident.
GUI programming exploded together with OOP, and a lot of libraries/toolkits were made when using OOP was almost mandatory.
As much as frontend programming gets a lot of flack, functional reactive is a much better paradigm. One can however argue it's just lacking better implementations for non-web applications.
> OOP is entirely about writing GUIs. (Well, the C++ idea of OOP.)
Nope.
One thing I like to do in C++ is, on an embedded system, wrap an object around a hardware resource. It means that no other code needs to know about the details of talking to that hardware. Also, if there are multithreading concerns, it leaves a very small set of places to worry about mutexes.
Ok, so you like to use OOP to emulate a module system.
Yeah, plenty of people like that too. That doesn't make it an application for OOP. The fact that the 90s killed the modular languages is quite a bummer, as neither modern FP nor C++ style OOP have anything nearly as useful.
Shallow dismissals aside, do you have anything of substance to say? I'd especially like to see your justification for saying "That doesn't make it an application for OOP".
FP languages will give you the exact same abstraction (not that you'd want to use any on a device driver). And before OOP was hyped and pushed everywhere, you could already get the same thing, but better (not on C, of course).
The fact that you need objects to get this on your current language is a bug, not a feature.
(There is the one version of OOP that most people call "multi-agent systems" that would bring very good abstractions to a driver, but it's not C++'s OOP, and you'd need a heavyweight library to get it there.)
What modular languages with "multi-agent systems" are you talking about? Please give some examples. The only domain where I saw "multi-agent systems" paradigm being used is AI, not programming languages.
> One thing I like to do in C++ is, on an embedded system, wrap an object around a hardware resource. It means that no other code needs to know about the details of talking to that hardware.
That, my friend, is modular programming. It is not specific to hardware, and not at all exclusive to OOP. In fact, C can do it just as easily as C++:
typedef struct {
// Private stuff, do not rely on it
int bar;
float baz;
} foo_ctx;
int foo_init (foo_ctx *ctx);
void foo_cleanup (foo_ctx *ctx);
int foo_frobnicate(foo_ctx *ctx, int frobnicator);
And if you don't like putting private data in the header file, we can have a pointer to implementation and hide it even better than idiomatic C++ (I don't like this much, because this requires allocations the above avoids):
Some would say I'm just emulating OOP in C. Except I'm not. There's no class in there, just a data structure with opaque data in it, and functions that operate on it.
---
I find it especially tiring when people use classes to do modular programming, call it "OOP", and assume it doesn't exist elsewhere, or was an OOP invention. OOP coopted modules, and put light syntax sugar to call it its own.
And I can already hear you scream that I'm "emulating OOP in C", though what I'm actually doing is emulating modular programming in C. And if we insisted on making it look like C++, there are indeed 2 missing ingredients.
The first one would be overloading on the type of the first argument. With that we would no longer care about name clashing, and could write the module like this:
typedef struct { int bar; float baz; } foo;
int init (foo *this);
void cleanup (foo *this);
int frobnicate(foo *this, int frobnicator);
The second missing ingredient would be syntax sugar so `f(x, y)` could be written `x.f(y)` instead. That way the calling code could really feel OOP, even though it's little more than a thin layer of syntax sugar.
I have even done it myself. Wrote a scripting language for a client who wanted OOP. Instead I gave them function overloading and universal call syntax, and they didn't notice a thing.
---
When you think about what OOP really is, there's not much. There's the idea of instantiation, where instead of using global variables you define a data structure and instantiate it under one local name. OOP made this popular, though I'm not sure it's not another cooptation. Any language that have user defined types can do that.
Then there's inheritance, which is mostly a mistake (in my experience inheritance is best avoided unless absolutely necessary — and it is almost never necessary).
And finally there's subtyping, which is nearly interchangeable with closures. It's a bit more powerful, but it is also a bit more cumbersome, and the added power is rarely needed in my experience.
---
Anyway, when one repeats the above often enough, there comes a time where one had enough, and just write a quick dismissal. When it comes don't to it the conclusion is fairly simple:
I agree that you can come very close to C++ with C. (After all, the original C++ implementation was cfront, which was just a C preprocessor).
But to me, the difference between C++ and what you're saying is this: If you say
typedef struct {
// Private stuff, do not rely on it
int bar;
float baz;
} foo_ctx;
The only thing defending bar and baz from my meddling is the comment. If you're in C++ and you make bar and baz private, then I can't modify (or even read) them without going through the interfaces you design. The larger the codebase, the larger the team, and the more average-or-below coworkers you have, the more that matters.
You're correct. Which is why in practice I often consider using a forward declaration and pointer to implementation instead.
But you know what, even that can be gamed. I have gamed it once: I copied & pasted the definition of the struct, and accessed its member from a place that was supposed to only have access to an opaque pointer. It worked. (To be fair, this isn't the kind of stuff you do by mistake, unlike merely accessing a struct member.)
Several patterns are trivial, others are very similar and are just a linked list of objects that are searched for performing some action.
The composition over inheritance meme in the book does not make things easier (there is no "composition" going on anyway, it is just delegation).
Objects themselves for resource cleanup like RAII are fine of course.