5 ms·
I doubt it. People aren't as dumb as you describe. Nobody is going to quote me without understanding or agreeing with me. A noob might pick what to learn based
by leafboi 6y ago
I doubt it. People aren't as dumb as you describe. Nobody is going to quote me without understanding or agreeing with me.
A noob might pick what to learn based off of what I'm saying (learn OOP btw, noob, it's bad but it's pervasive) but he's not going to quote something he doesn't understand or agree with.
>Meanwhile there are still millions of projects done with OOP, including super-complex AAA games, and more are being done right now...
OOP is not bad because you can't make things with it. It's bad because OOP abstractions do not add any real benefits while hindering reusability. That's all.
You can still build plenty of things with OOP. It's like javascript. A universally agreed upon bad language with stupid gotchas made in a week but pervasive due to circumstance.
- Const-me 6y ago> It's bad because OOP abstractions do not add any real benefits I like encapsulation of mutable state the most. Almost all software needs to read and write files, as streams of bytes. The state of the open file handle is incredibly complicated, besides the obvious size + offset it includes effective permissions, OS caches, inodes (linux) / NTFS (windows), and progressively more details on each level of abstraction. It’s not practical to expose all that stuff to a user who only needs to open a file and write a few bytes. OOP allows for nice abstraction over that mutable state. Here’s an example for C++ or C#: https://docs.microsoft.com/en-us/uwp/api/windows.storage.streams.ioutputstream?view=winrt-19041 https://docs.microsoft.com/en-us/uwp/api/windows.storage.str... Conceptually, procedural languages like C are doing that too for files, they’re just writing object.Verb as object_verb(Handle instance). You might reply “files are already implemented by OSes, no one is implementing them” and you would be correct. Still, many real-life I/O problems are conceptually (from software design viewpoint) similar to writing bytes into file handles. In networking-related code it’s not uncommon to layer multiple levels of network protocols on top of each other, OSI-like https://en.wikipedia.org/wiki/OSI_model https://en.wikipedia.org/wiki/OSI_model Hiding implementations of lower levels of the stack from consumers on higher levels simplifies a lot of things everywhere. OOP with interfaces is an idiomatic way to express that thing in programming languages. The benefits are collaboration (once the interface is designed, two persons/teams can independently work on implementation and consumer), testability (possible to replace the implementation of lower levels with a mock to test just higher levels), runtime dispatch (possible to build the protocol stack dynamically, e.g. either insert or skip the encryption), and modularity (different levels of the stack can be implemented in different DLLs, even by different companies).
- leafboi 6y ago>Conceptually, procedural languages like C are doing that too for files, they’re just writing object.Verb as object_verb(Handle instance). The main problem with OOP is the promotion of mute-able state, this is what ties everything together and makes everything less modular. Though semantically equivalent object_verb(object) is actually better than object.verb when you consider mutations and side effects. Seriously I want you to consider this: Two classes A and B. class A: def __init__(self, x): self.x = x heavy_computation() def addOne(self): self.x += 1 class B: def __init__(self, x): self.x = x def addTwo(self): self.x += 2 Let's say I want to write an addOne method for B. How do I reuse the code for addOne in A inside of B? 1. Inheritance. Make a base class have A and B inherit from it. 2. Duplicate code by writing a duplicate method. 3. Dependency injection, modify B so that it takes A and Does some crazy stuff: class B: def __init__(self, x, a): self.a = a(x) self.x = x def addOne(self): self.a.addOne() self.x = self.a.x def addTwo(self): self.x += 2 self.a.x = self.x All three options are bad for various reasons. There is no option where I can just add a method to B without modifying any other part of the program or duplicating code. AddOne is not reuse-able because it's tied to mutable state and the constructor and all the methods that share that state. This happens regardless of whether or not it's A.addOne() or addOne(A). The only universe where addOne can be reused is if it started off as a stateless function (addOneFunc) def addOneFunc(x): return x + 1 class B: ... def addOne(self): self.x = addOneFunc(self.x) By making addOne a functional concept I am able to impliment B.addOne without modifying anything else and reusing code to maximum effect. You cannot do this easily with OOP and this is why OOP is bad. If I want to deal with mutable state, it's actually not technically FP anymore. Inevitably I will have to and that's why many FP paradigms segregate IO with FRP patterns or the IO monad. Even still straight up procedural programming with mutability is still better than OOP because addOneFunc: def addOneFunc(int& x): x += 1 is more reusable than addOne: class Jungle: def __init__(self, x, gorilla, banana): self.x = x heavy_computation() self.jungle = create_jungle(create_gorilla(banana)) def addOne(self): self.x += 1 “… Because the problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle. “ —Joe Armstrong Many people will say don't design your programs this way. Well nobody has the foresight to know exactly how their primitives will compose for the design they have now and in the future. With OOP you will inevitably design your program into a wall because when it comes time to reconfigure the bricks in the wall you realize that OOP has super glued everything together. What happens IRL is that people eventually hit more complex versions of the example problem I gave you above.