Why is OOP still so widely spread?
stackoverflow.blog
stackoverflow.blog
What happens once something reaches the top is that you start to have people with lots of experience in it that are becoming more and more aware of some of the small warts. And they start to heavily complain about them.
The people with less experience listen to those complaints, but don't have the understanding to the nuances and minutiae involved to really understand what the problem is and how big a problem it is, if it means the entire paradigm is garbage, or just some details that can still be improved on, and other small things where there might be better ways to approach it.
So, the less experienced start to think it must just suck. And they don't want to spend their effort learning something with so many issues that clearly some of the smartest devs say has tons of problems and there are better approaches for.
This eventually leads to the cultish flame wars and all that which we see way too often when discussing technicalities. The problem being, most people do not actually understand what is bad or good and the trade offs at play, thus when they debate, they instead pray on their affiliation and beliefs of what they've read but did not properly understand.
You can see this on display in virtually every hackernews thread. Somebody will say something like "I sort of like X, but my problem with it is Y". But what they don't tell you is their experience level, the context of how they came to believe Y, or really any supporting understanding of whether Y is an actual technical tradeoff that needs to be considered. It's sort of an overly grandiose, performative way of saying "oh yeah I tried haskell once, and I got stuck on this thing, so I never came back to it."
As one of the novices just trying to allocate my time, I'm constantly trying to understand whether, say, it's worth really understanding C++ at a deep level, or whether I should just try to learn Rust. All too often, I find this devolves into me scouring the internet for "C++ is ok but the ownership model is so primitive that I would never start a new project in it" and comparing it to "My problem with Rust is that it's still such a nascent language I can't trust it to have the libraries I need". Who are these people, and why are they saying these things? Are their gripes relevant to me? I have no way to know!
Reading some comments on hackernews, I often come up on a comment that seems to be speaking another language. At first I'm intimidated into thinking that there's a secret club of intellectuals that understand exactly what this comment is talking about. But then I start to wonder.. is this actually elite minds speaking in a very high-level way with extremely advanced context? Or, is it just some overly opinionated junior person who just assumes everybody is working on the same web tech stack they are, and speaks with that implicit assumption? When they say "OOP is now considered an anti-pattern, most companies are moving towards reactive FP", do they really mean "I work at snapchat and the ads group I work for is moving away from OOP. My friend at amazon said he's doing the same thing"?
I love HN don’t get me wrong, but my coworkers and I like to poke fun at it. Some jokes are “why didn’t you just use rust?” and “Well what did Paul Graham have to say about it?” when debating something. It’s a culture like any other. I would say a lot of super smart people are here, who have deep knowledge on the most esoteric niche subjects, and provide a lot of sage wisdom and advice. But there are a lot of cranks too (including myself!).
Yes, thankyou! I think about this every time I see "Systems are so powerful we can just throw RAM/CPU cycles at every problem, efficiency doesn't matter..." as if everyone on the planet is doing web apps, and there are no engineering/architectural situations that might drive certain languages or design principles. Such as this:
https://www.intel.com/content/dam/www/programmable/us/en/pdf...
I guess I'm just focused on a niche market...
Think about languages as tools: focus on the tools you need to use. Your career will be long and there will be plenty of time to branch out, but you have very limited time for mastery, so you should master the tools you use often.
All too often, I find this devolves into me scouring the internet for "C++ is ok but the ownership model is so primitive that I would never start a new project in it" and comparing it to "My problem with Rust is that it's still such a nascent language I can't trust it to have the libraries I need". Who are these people, and why are they saying these things? Are their gripes relevant to me? I have no way to know!
Honestly, just pick one and run with it. Part of becoming an experienced programmer is developing your own heuristics for how to pick the right tool for the right job and how to read this type of discussion, and a big part of that is building up both wins and losses to train your intuition.
When they say "OOP is now considered an anti-pattern, most companies are moving towards reactive FP", do they really mean "I work at snapchat and the ads group I work for is moving away from OOP. My friend at amazon said he's doing the same thing"?
If it's an internet forum and you don't see references or citations, it's probably safe to assume it's the latter. They might still be right, but not verifiably so.
Try not to get bogged down by what others say. If you’re looking for a job in a particular industry, follow the fads of that industry. Otherwise, just keep building your knowledge and worry less about whether it’s the right specific technology.
There's another dimension of the issue: types of the project the person has experience with.
Something that works in a low-level Windows desktop doesn't necessarily work in high-level Linux web. Something that works for NASA or SpaceX doesn't necessarily work for a mobile game startup. Something that works for FAANG is not necessarily the best way for a web site that's running on a single server. Something awesome for a social network is not guaranteed to do any good for a bank, or a research lab.
That "something" can be pretty much anything: languages, libraries, IDEs, frameworks, project management practices, hiring practices. The only thing these projects have in common is "people need to write code that does something". Almost everything else is different. And yet we have many discussions where people working in different industries, on projects with different requirements, budget, users, revenue sources are arguing which language is better.
I think it's lazy to dismiss the OOP as hate from experts who are complaining. I think a lot of criticism for OOP comes from experts who used to program in OOP, often with decades of experience, and have moved on to other paradigms, and are proudly proclaiming "I will never go back". If you want a really good (non-individual) example, take React, yes, the framework as a whole, which has quietly migrated away from OOP to promoting FP style as best practice; and hell, this is inside of a programming language that while proclaiming to be multi-paradigm, was very much created with Object Orientation in mind (yes, I am aware that it was supposed to be a lisp at one point, but almost everything in the language is Object object).
I think there's good evidence that this isn't just a run of the mill "grass is greener" grousing by experts. Here's a challenge. Can you name a contemporary expert or a platform that started or spent a good chunk of time as FP and ran back towards OOP (I would say since 1990 or so, as it is a thing that FPs had very poor performance before that era)?
I'm sorry if this is what you understood. The hate is from people hearing the complaints of experts. The experts generally have great understanding of the pros and cons, and are aware of the weaknesses, which they will openly talk about and sometimes that will make it sound worse, almost hyperbolic to others. Even I'm faulty of doing this, I might say this just sucks, or it's total rubbish, but really I mean it's pretty good and there's a lot of good ideas and parts, just needs some refinement and a few modifications because there are still problems with it, and I just faced one such wart so I'm frustrated and writing a big blog post to complain about it.
And this is the source of the misunderstanding. Overreaction and hyperboles from experts, taken at face value to those who are learning about it.
To your other points, I think it's interesting you bring up React since its biggest competitors: Vue, Svelte and Angular are all OO based and seem to be doing well.
> Can you name a contemporary expert or a platform that started or spent a good chunk of time as FP and ran back towards OOP
Hum, I think most did. OCaml added an object system to ML. CommonLisp added an object system to lisp. Haskell added TypeClasses. Scala is an attempt at an Haskell like language with a full object system. F# and Kotlin both have object systems as well. One could argue actors are a purer form of OO. And so on.
See, my point is that experts only ever complained about certain aspects of current iteration of so called OO programming languages. And as you can see, alternate languages they'd reach for or newer languages after them (or even newer version of those languages) all tried to address those shortcomings, but did not throw the baby out with the bathwater. There is convergence of ideas, and most of those languages have many if not most of the OO staple feature set, while having taken a few out or added some other inspired often by FP, but sometimes by other paradigms too.
Haskell type classes have nothing to do with OOP in the least, and as far as I know, Ocaml is a counterexample rather than an example to your point: they included OOP becsuse it was all the hype at the time of conception, but the OOP features are really quite unpopular today.
As you were completely off with Haskell, I can't exactly trust that you're right about any of the other languages "running back to OOP". If anything it seems to me the languages that started out as multi-paradigm FP/OOP have become more purely FP over time, as OOP has failed to prove its worth.
I’m not sure. For example, frameworks are often nicer in OO than FP. Of course some wag will suggest you shouldn’t use frameworks, only libraries, but that misses the point.
Plugins strike me as another use case that works better in OO than FP. I’m certainly not saying you can’t have a plugin architecture in FP though, it just won’t be as nice to use, that’s all.
I expect in a few years the OO revival will be strong. “Look, we can neatly model fundamental concepts such as timers again!”
>> Can you name
Does es5 to es6 count? es5 was in theory already OO but the predominant usage appeared to be more heavily influenced by FP. I could be wrong on that but books like javascript the good parts were popular.
There are some very nice FP frameworks, for example Phoenix LiveView, or phoenix in general. Elixir has lots of mini-frameworks (like the Enum and Access protocols). They're a joy to work with and pretty easy to understand. I'm not really sure what constitutes a plugin, but I've written what I would consider "plugins" for the BEAM vm (loaded at runtime, with an exposed API behaviour called into by the system), and they're pretty smooth and easy to handle.
Arguably all of the BEAM OTP (std lib) and the patterns that packages expose for building persistent services are FP frameworks. If I may be permitted to make a more apples-to-apples comparison between the Erlang BEAM framework, to the BeOS C++ framework (both highly concurrent message-passing, actor frameworks). While I loved programming for BeOS, IMO doing everything functionally is far far smoother an experience than doing everything with objects. Both I enjoyed far more than programming the Dalvik (android) Java framework (though that was circa 2009).
Anyways having experience in all four quadrants, I don't think it's as simple as ("frameworks/plugins -> OOP; libraries -> FP).
It's also hard to argue that Whatsapp hasn't been wildly successful at scaling to a billion users on a miniscule engineering team in spite of "impracticality of FP".
My company has 200 Java engineers, and a dozen systems written in Java; it's not practical to migrate everything to <FP language>.
Spring Boot solves so many things out of the box that I'd have to implement myself in <FP language>, which isn't practical.
FP has a lot of features but it's not practical to maintain a large complex codebase using those features.
React is probably not a good example, because it didn't really expose its users to the horrors of OOP. There wasn't much inheritance and subclassing going on in the userland; you didn't really see SecondaryButton component inherit from the Button component and override its "render" or "onClick" method. True, there were some such codebases, but it was extremely rare. So no, I don't think React users have ever experienced the full extent of OOP, where you have to hunt through your codebase up the hierarchy chain for the bit of code that is misbehaving.
I can't think of a time where we killed a project or rewrote a project to make it more functional. Or where OOP bite us.
React went functional for a reason. Does everyone share that reason?
Because that means people who wouldn't have picked the tool themselves are now forced to work with it.
That causes a WHOLE NEW level of complaining!
Another way of putting it is that the most hated tool in a field is almost always the most used one.
It doesn't take any depth of experience to say "oh, it's a tradeoff, there are no good or bad techniques, only tools in your toolbox". It sounds wise. But often it's plain wrong.
The reality is that the difference between general purpose languages aren't that great. Even when highly conservative languages like Java adopt functional programming elements, they don't really add capabilities, they only change convenience. Lambdas are nicer than anonymous classes but they are still equivalent in functionality. The situations in which you absolutely need a purely OOP or FP focused language are pretty rare. People need a language that does a little bit of everything but doesn't go too deep into either end. The problem with feature rich languages is that they are ripe for abuse. When someone discovers a feature for the first time they are going to test it out. People produce a lot of crap in their learning phase that should be thrown out but it ends up in production code bases.
It's not even that -> there is not 'hate' but among a fairly small group.
There is no general movement among the rank and file devs against OOP, nor among leaders.
It's really just a specific group.
More to you point - all incumbent systems have 'arbitrary antagonist'. It doesn't matter who is in charge, who is #1, who is the best, there will always be vocal critics.
When in truth they’ve simply formed an echo chamber for their own loudly-stated views.
I don’t like object oriented programming
It falls apart when your project gets large
There’s too much performance penalty
It requires you to structure your code (?)
And this is in the year 2020.That’s a bit abstract. Basically a lot of good cake from OO. It’s not all good, sure, but polymorphism is a pretty darn good idea. Substitutability is a good idea. OO won’t solve all of your problems for you, but it isn’t inherently creating your problems either.
Well hate is too strong of a word. I don't hate OOP, but i definitely think it's a mistaken paradigm.
I think there's actually an opposite phenomenon going on side by side with the one you discussed.
Too many senior programmers are really great experts at OOP while never really examining the faults or mastering alternative paradigms. The time invested into OOP leads to a huge bias in favor of it. When OOP is evidently (to me) too be worse than procedural programming and FP people are unwilling to give up years of time invested into OOP. When experts decry OOP of course someone with 10 years of experience in JAVA is going to object. That's the way people work.
The bias comes from both directions. If you think OOP is pretty good and everyone else is biased... ask yourself are you a master at OOP and FP or just OOP? If you're great at both paradigms and the time invested into both paradigms are equal... than you have the ability to make an unbiased choice. Until then most people on this thread are java guys promoting the skill they've been honing for years.
A master carver isn't going to decry his years of training just because a 3D printer can beat him at his game. Humans don't work that way. This is mostly what's going on.
There are other programming paradigms and there are of course multi-paradigm languages. As a for instance I do most of my work in Prolog these days (because PhD) which is a logic programing language, so neither OOP nor FP but, er, well, LP. There's many logic programming languages that mix multiple paradigms like Logtalk (LP and OOP), Visual Prolog (LP and OOP) Mercury (LP, OOP and FP), OZ (LP, OOP, FP, constraint, concurrent) etc etc.
I mean, I understand that OOP and FP may be the only relevant paradigms in a particular context- but, in that case, what is the context that is assumed in this thread? Web development? App development? Games development? AI? Data science? Embedded systems? Compiler writing?
EDIT: I guess this "OOP or FP" thing reminds me of myself at my first undergrad CS year. I knew a bit of JS/HTML/CSS, a bit of Java and C#, a bit of SQL and had heard of C and C++ so I was trying to place them into categories, like "C#, Java and C++ are OOP, C is procedural, that's it, there's no other paradigms". Then, in the second year I met Prolog and it kind of blew my mind. It's good to have one's mind blown like that, though it stings at first when one realises how little one knows and how many assumptions one built on such little knowledge. One feels a little dumb. But one quickly gets over it because there is suddendly a world of interesting new things to learn.
Thank you for demonstrating my point :p
This is exactly what I'm referring too. The use of hyperboles or blanket statement by experts, which are taken at face value by those learning from them. Whereas your real sensibilities are well reasoned, nuanced, and your disliking of OO is in the details. Not everyone can get that from your reaction. So it creates this fashion trend, it's trendy to hate on OO. That's not constructive, because experts also know there's a lot to learn from OO, and not everything about it is bad.
Most importantly, not everyone hates it. There are definitely warts involved, and IMO the 2 biggest warts are now largely understood:
1. People understand the pitfalls of inheritance now, so you'll see "composition over inheritance" MUCH more than you'll see inheritance as the recommended way to do things.
2. I don't know how widespread this feeling is, but as someone who moved from Java to Node/Typescript a couple years ago, I feel like I can confidently say structural typing, in practice, is MUCH easier, better and fun to work with than nominal typing. I can think of times I literally spent days trying to work through some refactoring in Java that was a nightmare because of the constraints of nominal typing, where the structural typing approach of TypeScript makes it trivial.
Structural typing is crazy flexible, but you pay for it with worse type error reporting (forgetting something in an interface is now 100 errors rather than 1) and the inability to encapsulate (a structure type can't model private members, of course). There was a lot of research in addressing these problems in the 90s, but for some reason none of that work has made it into any mainstream structurally typed language today.
I'm developing a structurally typed language now. Is there some research you could recommend me?
So much that you'll have people advocate doing inheritance using interfaces and composition which results in exactly the same thing with all the same pitfalls but at least it's not "inheritance".
Object mutability is an attractive nuisance.
Which is a shame because I like bits of OOP.
The obvious takeaway here in some respect is gradual typing is better and nominal typing is annoying for little gain.
What if the true answer were you need a more flexible and powerful type system.
I think that moderate so-called "pragmatic" languages are the worst experience because of their lack of guiding principles.
There can only be widespread hate for things that are widely used.
TIL it has name! And I share your opinion, it's much easier, especially when doing immutability due to property spread, etc.
Agreed that structural typing is nice, but it's not restricted in any way to OOP.
Totally agree, but what I'm arguing is that a lot of the pain points people associate with OOP are actually more about the pain points of a nominally-typed system, and when you use OOP with a structurally-type language a lot of those pain points go away.
That's the issue with these kinds of topics. For me, it's the other way round. Having worked with golang on significant code bases, the way they handle interfaces is just terrible IMO. It's been quite friction heavy, and loses out on one of the most important part of nominal typing: being able to use interfaces to tag classes. The hacks you see in golang to get around it, while introducing dangerous behavior, is quite astounding.
Go find some old C code for doing something like compressing a file. You'll likely find a set of functions where the first or last parameter is always a pointer to some struct or array with the current state of the compression process. If you converted that code to C++, and made it an object, that pointer would be the "this" pointer. The support for objects is just recognizing the common pattern.
Inheritance is similarly recognizing that a lot of code had structs or arrays with multiple function pointers.
The language support just makes those patterns a bit cleaner and less error prone.
There's nothing you can do with OOO that you can't without it, and vice-versa. At the end of the day all we have are instructions and data.
Even when you elevate a particular construct to be first-class in a language; the expressiveness of languages differs greatly.
For example, prior to lambdas, first-order functions existed in Java in the form of static methods - but higher-order functions weren't really possible. Even now, we lack the ability in Java to express certain forms of functions which are possible in more expressive functional languages.
Lisp's in general have the same control constructs as many imperative languages, but it's possible to do higher-order abstractions over them through the use of macros and constructs like shift/reset or call/cc and the fact that everything is a s-expression.
In this regard, Java and C-like struct pointers are almost first-order OOP languages - the composition via inheritance is quite frankly poor compared to the other paradigms.
I see you have never used Swing. The reality is that when you needed a callback there were interfaces with a single method and you created anonymous classes that implemented that callback and its method. It's clunky but it's equivalent to higher order functions.
void mything_somefunction(MyThingStruct *mything, ...args){}
The weirdest thing was some of the crusty C guys in my group saying "Eww, is that objects?" No, it's maintainable, and it avoids collisions.It's even more strange now, that we have distinctly non-OO languages that explicitly use the first-parameter-is-struct pattern, e.g:
struct definition: https://github.com/elixir-lang/elixir/blob/v1.10.4/lib/elixi... and functions: https://hexdocs.pm/elixir/Date.html#functions
In OOP you can have multiple functions that are called "save" and they are primarily distinguished by their type. If you define a static function in Java you call it by invoking its namespace:
MyThing.somefunction(myThing, args)
Alternatively your function is bound to an instance of an object. Then the save function is chosen based on the type of the variable you are calling the function on.Compare this to Haskell records. Field names are not defined inside a type dependent namespace and therefore you cannot reuse field names in a second record. If I remember type classes correctly they allow you to define implementations sharing the same function name, but they don't allow you to have multiple type classes define a function with the same name so they do not offer type dependent namespaces either.
OOP tends to make organization easier because of this namespacing feature. It probably has led to "over-organized" codebases though. Too much of a good thing can also backfire.
That is the thing, at their basic level, objects are just some form of extensible modules.
Yegge's anti-OOP rant is mainly about this design in Java. Norvig's presentation on design patterns points out that some OOP tropes are compensating for missing non-OOP features like first-class functions.
Python's standard library is a good example of how to use OOP effectively. For example, `multiprocessing.Process` is a class because it explicitly manages state.
There are two biases skewing perception, too: the first is simply that people using other languages or writing newer Java well are probably not writing blog posts about how their language is less hassle than the business.
The second is that OOP is so much more popular that people forget to adjust for things like skill levels for a mainstream versus niche language. There are tons of jobs in OOP languages so there’s a ton of code written by people who weren’t going to write great code in any language, whereas a lot of less widespread languages - especially those built around an academic concept - will self-select programmers who are trying to improve their craft. This is telling you more about the job market and how much companies value quality than the languages.
There's also not a huge benefit to having data.sort() vs Array.sort(data).
OOP is a lot more than that. One can argue its great, one can argue it sucks, but either way, a bunch of methods grouped together isn't really what is being debated.
I think when everyone talks about OOP today they mean the lineage that descended from C++, which broadly is: Java, Javascript, C#, Python, and Ruby, to a lesser extent Go.
Contemporary OOP is the enforced semantic association of data with their methods, encapsulation of private data, and shared memory.
The benefit of `data.sort()` is you could write that in a function that accepts a `data` that could be an array, a vector, a linked list, etc... anything that implements the "sortable" interface. Writing `Array.sort(data)` in your function means the function won't be usable for any kind of data other than arrays.
The other features of OOP like encapsulation, inheritance and abstraction -- these aren't so special. But OO polymorphism is pretty unique.
It's not. Julia uses multiple dispatch so that you can use the same * operator on integers, floats, complex numbers, quaternions, matrices, matrices of quaternions, galois field elements, and then it's sophisticated enough that if you implement a new type with +, -, /, etc. you can get matrix solving from the standard library for free. So you just implement + - * / on the GF(256) and you can do reed-solomon erasure repair, hell, in quite optimized code trivially without rewriting LU decomposition.
Other FPs have solved the polymorphism question in their own ways as well (protocols are a common scheme).
I think the first one feels a lot more natural. It also seem to lower the cognitive load of knowing where to find the sort method / function. Is that just because I have used mainly OOP style languages?
A fairer analogy would be to say that OOP is a particular architectural style, and FP is another.
You can mix Japanese woodworking with European woodworking by using screws, nails and glue whenever you feel like it. Its simpler than pure Japanese woodworking, not as pretty, quicker to construct, doesn't last as well. You can even forego Japanese woodworking entirely, but to do so is to throw away an entire culture's worth of knowledge about how to cut, shape and join wood, so likely not a great idea.
I, personally, am a believer in minimalism. Features which experts tell beginners to avoid should be removed. That's very hard to do with programming languages that need to support legacy code though. So I always look for new programming languages that try to do things differently, with as few features as possible.
Analogy: You talk to some master chefs. You tell them that the sharp knives are dangerous; they should get rid of them. They're going to tell you to get lost. The knives are valuable to them precisely because they are sharp. Sure, an amateur like me could seriously cut himself on one. So?
OK, "I wouldn't work on such a project" is a fine answer. But not a universal one.
1) performance bottlenecks are generally no longer CPU computation (network tends to dominate for many many things), and there is nonzero overhead to most functional operations.
2) coordination-free concurrency can in many cases often overcome computational bottlenecks, and non-OOP is far more effective for the code author in dealing with/grokking concurrency.
3) in the intervening time, functional patterns for some things (like UI) have been discovered which make fp a good fit for things that in the past were understandably the domain of OOP.
In order to build reuseable components you need components that compose well. Object composition does not allow for composition without specific glue code for each integration.
For example:
functions addOne and addTwo can compose to form addThree with a single general function composition operator, no glue code needed and no need for addOne or addTwo to be aware of each other. (addThree = addOne . addTwo)
OneAdder and TwoAdder cannot compose without specific glue code or specific interface code to allow for DI. ThreeAdder = composeAdder(OneAdder, TwoAdder) would be implementation specific. Additionally ThreeAdder(TwoAdder, OneAdder) makes ThreeAdder aware of TwoAdder and OneAdder. These are not qualities of reuseability. The existence of a mutating object breaks reuseability.
OOP does have it's use cases but the hate does comes from somewhere. One of the main downsides of OOP is the fact that current practices makes it one of the least reusable paradigms ever. DI and object composition are illusions. That being said it's not all that bad... not all business apps need the form of extreme reuseability that FP provides, so OOP is often good enough.But OOP languages do have lambdas and function pointers, so can easily do something very close to that. In Kotlin:
fun addOne(value: Int) = value + 1
fun addTwo(value: Int) = value + 2
val addThree = fun (value: Int) { addOne(addTwo(value)) }
There are libraries that add a pure functional composition operator via a + operator overload, I think.Even in Java you can do function composition, though it's not well known and a bit verbose:
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
static int addOne(int i) { return i + 1; }
static int addTwo(int i) { return i + 2; }
void combine() throws Throwable {
var lookup = lookup();
var type = methodType(int.class, int.class);
var first = lookup.findStatic(Main.class, "addOne", type);
var second = lookup.findStatic(Main.class, "addTwo", type);
var combination = filterReturnValue(first, second);
System.out.println(combination.invoke(1)); // Prints 4
}I, however, often see objects used in bizarre ways. Often to reduce written lines, or to take a concept, and attach another concept to it in a fairly ad hoc way. This is never helpful.
The most problematic times i have with object is when the concept behind them become too general. E.g. If a have a program with a deck of cards, i can have card objects, with rank and suit, and i can have deck objects, with 52 cards, shuffle and deal methods. That's fine, but if i have an object that's just "poker game" that tries to shove all those concepts into one object, it seems to become very unwieldy, very quickly.
This is painful use of OOP (actual code from an Android app):
Camera.Parameters params = mCamera.getParameters();
params.setRotation(90);
mCamera.setParameters(params);
This would be NICE use of OOP: mCamera.setRotation(90);
OR mCamera.setParameters({"rotation": 90});
This is painful use of OOP: BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 4;
Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length, opts);
mImageView.setImageBitmap(bmp);
This would be nice use of OOP: mImageView.setImage(new Bitmap(data = data, sampleSize = 4)); Camera camera = createCamera({"rotation": 90});
If you need another camera with different parameters then create a new one. You can build the options before the creating the cameras to avoid duplication. Bitmap bitmap = createBitmap({data: data, samepleSize: 4});
ImageView imageView = createImageView(bitmap);
In the case where you are mutating image view, it's an optimization to reuse the same memory that could be handled by your language/framework so you don't have to think about it. For example, like with react it could create an internal representation of what is rendered and then diff it with the new rendering and reuse the internal representation of image view and mutate it for you so you don't have to think about doing the optimization yourself.These sorts of objects provide a nice API, but they don't contribute to good internal designs. I have seen many systems were there is an attempt to map objects to physical things (like on a modem, you might have a "demux" object). Invariably, software ends up having to bend to the design of the hardware, and you end up with very leaky abstractions. Why have a "demux" object, when all you are trying to do is write some registers depending on user configuration? Why not design your software around what it is actually doing, rather than what the system's overall purpose is?
Interfaces are a different question. High level interfaces that reflect what the system actually does are very useful. I think this is born out in some modern OOP-ish languages like Go or Rust where interfaces are everywhere, but full scale OOP is mostly absent.
camera_set_rotation(camera, 90);But sometime it is too verbose to use OOP, for example lambda vs anonymous listener. The biggest problem is it is easy to do wrong abstraction with OOP style, for example, store state that make no sense and put weird method inside a class
Everyone I know loves OOP.
I am primarily a Ruby developer so I know I'm in a bit of a bubble but still... The title is pure click bait.
In meatspace, everyone I know is fine with OOP. Usually it is other aspects of the programming languages that result in griping.
I have seen people write entire systems in DOS batch script. Was that a good idea? Not really. Can it be done? Oh very much so. But is that the fault that DOS batch script let you do that? Not really.
OOP is the same sort of thing. It is a tool. You can take the abstraction too far and make it miserable to use and extend. It depends on the team/person doing it. Perhaps they are fine with 'too far' the next poor soul to come in may not be able to keep up with the 13 layers of abstraction that they had no decision in. Where is that line? That is more art than CS as the rule is 'it depends'.
Seeing code that goes all in on OOP absolutely makes me cringe as I know it generally means the unit tests are going to be more complex than they would be in an FP environment, the code's likely going to be harder to extend as there's no amount of class inheritance planning that can prepare you for all future business requirements, and in most cases it's just going to be so much more verbose than an FP solution would be (I know this last point is a bit of a personal issue).
Code that goes all in on FP I absolutely love on a pure nerd level, but absolutely hate on a practical level. Pure FP is neat in the same way that seeing someone who can calculate out pi to a hundred digits is neat. Sure it's impressive, but like... I got this calculator that will handle it much easier.
There is also a big difference if you're working mainly on the backend where you shouldn't keep any state or the frontend to how useful many OOP concepts are to you.
Inheritance got caught up in the "is-a" mindset of 1980s AI, and turned out to be only marginally useful. Being able to have an object as a field of another object is almost as useful. A point I make occasionally is that there needs to be a good way to find the owning object when you do that. Is there a language where, when B is a field of A, you can find A from B? I've plugged for syntax for finding the owner in Rust, where backpointers are difficult.
Order of initialization for inherited objects is a huge headache. If B inherits from A, what in A is B allowed to call or reference during construction? This sort of thing needs language support. Same for order of destruction.
Multiple inheritance is usually a mistake. If you reach the "diamond pattern", your code is too cute.
I've built this multiple times in Python in a few different ways. Metaclasses work (for e.g. declarative stuff, like in ORMs and data description), the descriptor protocol works for the runtime kind (caveats ensue).
> Multiple inheritance is usually a mistake.
Allowing multiple inheritance seems to work better in some languages than others. For example, in C++ it almost always seems to be a bad idea. In Python it tends to work out more often (usually when the other classes are pure mix-ins).
Modules usually have data types that can be instantiated via functions/procedures in the module that let you avoid global data. They don't have to have data fields in them that are changed directly by the procedures (giving you, effectively, singletons).
It's not unusual in system/kernel C/C++ code to do that with offsetof() macro.
Most mainstream OOP languages support it in some form, and it is quite useful, specially when considering single responsibility principles.
Like everything else, it can get abused.
I'm not sure what language you are talking about where you have "one set of data", maybe BASIC?
There are almost no modern languages save perhaps Javascript that rely on global data extensively. (and even modern Javascript has moved away from use of global variables).
The Hibernate ORM framework for Java supports this paradigm.
OOP works on low complexity, small projects, but quickly falls apart at certain point, but then it's just head scratching and finger pointing ("this ORM is just bad, next time we will use a different one").
More experienced people figured out some way around OOP to make it more robust, so whenever OOP is criticized they just do the "oh, you just doing it wrong: insert excuse and advise here".
People who really though it through, and tried different approaches are the ones that hate it and are vocal about it. They see through the folly. They can tell how core principles of OOP are bad ideas. How encapsulation at object level is usually pointless and costly, how inheritance doesn't make sense, and so an so.
Just saying "if you are really smart you'll see that oop is bad" just sounds so... Empty.
* "Everything is an object". This creates unnecessary confusion between data and modules and sometimes even functions.
* "Everything is a message". This encourages splitting state between a myriad of objects, each hiding some tiny bit of mutable state that changes whenever it receives a message. Reasoning about such a state graph is impossible for any non-trivial application.
* "Everything is an interface", which leads to tests tightly coupled to implementation due to mock over-usage.
* "Everything is an inheritance hierarchy". Practice has proven that composition is better than inheritance.
Traits feel more natural to me. Instead of needing to make a subclass of a data structure to attach a foo method to it, you can define a collection of foo methods with the same name and pick the runtime implementation based on data structures passed to the method. I understand that this six of one, half dozen of the other, but I do prefer it this way.
Granted, this is not something OOP does "wrong," and you can use generics to accomplish a similar thing, so it's not that big of a deal.
I fully accept that not everything benefits from being expressed in objects, which is why hybrid languages like Python are so excellent. But yes, even if some things don't map, keeping OOP around for things that do makes too much sense to ignore.
OOP only provides illusions of reuse-ability. In reality every component created in OOP takes extra steps and extra glue code to make compose-able.
In programming you want to build small primitives that you can compose to form larger higher order primitives. This allows you to reuse lower level components to form new programs. OOP does not allow you to do this easily.
ORMs that overload getters and setters as DB transactions: It creates a harmful illusion that the data inside the object are equally as authoritative as the data in the source of truth (as in database).
OOP really hasn't been given a fair shake. On the academic side, people figured out pretty early on that OOP doesn't mix well with an imperative programming style. It undercuts the basic idea, same as for FP. But the siren song of multi-paradigm programming is hard to resist. So the tradition of OOP that started with C++ (and ultimately displaced what the academics were working on) was basically an experiment to see if you can improve the flavor of cow pie by mixing it with apple pie. It turns out, no, not so much. You don't really make the cow pie any better, but you do make the apple pie much, much worse. Unfortunately, few people realize it's even possible to do OOP without all the BS (pun intended). Most of us have never known anything but this tradition that basically ignored everything that happened during the 1970s, rolled the universe back to the state of the art as of Simula 67, and took over the world by reassuring managers that nobody was going to try and take away their precious lowest-common-denominator imperative code.
I mentioned elsewhere in the comments that Alan Kay once stated, in so many words, that to him encapsulation was about getting away from an imperative, stateful way of doing things and moving toward a much more declarative style of programming. Being able to do that was a key strength of his formulation of OOP. And it's hard to deny that he was on to something. What his lab was able to accomplish, in so little time and so few lines of code, should be enough to give anyone pause.
But OOP is now strongly associated with bloated and sprawling codebases, not smaller ones. And enabling people to rise out of the imperative programming tarpit and adopt a more declarative style is now commonly cited as a key advantage of FP over OOP. Clearly, something was lost along the way.
...pretty sure there are competing abstraction layers to working with DBs other programming paradigms.
> OOP works on low complexity, small projects, but quickly falls apart at certain point, > More experienced people figured out some way around OOP to make it more robust,
I thought it fell apart?
> "oh, you just doing it wrong: insert excuse and advise here".
Wait til you learn what point-free style is in Haskell! Have fun!
> People who really though it through, and tried different approaches are the ones that hate it and are vocal about it.
So if you happen to like OOP, you just haven't thought it through. Thanks for the constructive comment!
>> Wait til you learn what point-free style is in Haskell! Have fun!
I honestly don't understand what you're trying to say here. Care to elaborate?
As for ORMs: no, other styles of programming don't have this particular problem nor competing abstracting layers approaching this level of chaos. The ORM addresses a specific mismatch problem between relational databases and objects from OOP. This problem is so messily unique that it has been aptly named "The Vietnam of Computer Science": http://blogs.tedneward.com/post/the-vietnam-of-computer-scie...
Some very large project, like Windows and all major browser browser engines (as far as I know) are written in C++.
Can you explain these? I'd like to know why people think encapsulation and inheritance don't make sense.
On encapsulation: I joke that encapsulation on a level of an object is like putting a lockpad on your right pocket to protect your left hand from reaching to it.
Normal people keep doors and locks at the entrance of a door or a room (module level), not on every single object they have. That's why OOP software tends to look so schizophrenic: with walls erected between everything against everything, making stuff like https://github.com/Hello-World-EE/Java-Hello-World-Enterpris... possible.
You might check some of my blogposts at dpc.pw if you care to read more of my thoughts on this.
As others have pointed out, everyone has a different definition of what the core principles of OOP are.
When Alan Key coined the term "object-oriented programming", he had message passing (among other things) in mind. If you like that definition, stop reading this and go use Erlang. If you were more thinking of the various modern languages we now call OOP, read on.
The "lies for small children" version is that OOP is all about modelling the real world in a natural way: apple.eat(), car.drive(), etc. Nouns are objects and verbs are methods. From my POV it's a strawman to reduce OOP to this, but I bring it up because some people like it this way and will argue for it - "It's a natural way to think about software", etc.
How are nouns and verbs actually modelled in practice? You don't file.read() and file.write(), you construct a FileReader and FileWriter, and you tell them to read() and write(). The verbs ofen show up in class names (fileREADer). It's delegation of responsibility and I argue it's a good way to design software. But delegation of responsibility is not restricted to OOP.
Putting aside modelling and design concerns, what are the core features of OOP languages? I like the Uncle Bob definition of Inheritance, polymorphism and encapsulation.
Inheritance:
Inheritance is fraught with more "lies for small children". A Lion is a type of Cat which is a type of Animal. I admit this is another strawman because using inheritance to model taxonomies like this is dumb and doesn't happen in the real world. How is inheritance used in the real world? I honestly don't see it that often. A lot of frameworks like to hijack your 'main' method and force you to use inheritance to run the thing, e.g. MyApp extends SpringApp. I keep trying to think of inheritance examples and think "no, that's just an example of using an interface".
Anyway, one of the principles in the OOP body of knowledge that has emerged over time is to "favour composition over inheritance". You might get to share some behaviour and cut down some code between 2-3 classes, but on the flipside, now when you want to modify just 1 class, you have to realise you're modifying the other 2 classes as well.
Elsewhere in the OOP body of knowledge is the five SOLID principles. I love SOLID. Someone familiar with SOLID might say "but we know how to safely extend classes because of the (L)iskov Substitution Principle!" But it's not an instructive way to safely use inheritance. It basically says "don't fuck up inheritance".
Polymorphism:
Lots of languages have polymorphism. I mainly use Java and I'm disappointed in its polymorphism story. Perhaps other OOP languages do it better? Java has interfaces/abstract-classes as well as "Generics" (first-order parametric polymorphism). First-order parametric polymorphism will let you model List<Integer> as List<I>, but it will not let you model it as L<Integer>. Why does this matter? When you want to abstract over things that are "mappable", like Optional and Stream.
<U> Optional<U> map(Function<? super T,? extends U> mapper);
<R> Stream<R> map(Function<? super T,? extends R> mapper);
I can't do this: <U> F<U> map(Function<? super T,? extends U> mapper); // The F stands for "Forbidden" !
I have worked on a large codebase where one of my tasks was to move from Guava Futures to Java 8 CompletableFutures. I really would have liked the ability to hide those concrete classes behind some kind of abstraction. Incidentally later on one of my colleagues said he'd like to rewrite it using Observables. At a different company one of my coworkers went the other way - he did a "hack week" project of converting a codebase from Observables to Futures. It would be better if you could just leave the business logic generic and instantiate it over an Observable or a Future as you saw fit. I don't know OO languages that let you do this.Encapsulation:
I think the most promininent definition of encapsulation is you hide data inside an object and only manipulate that object using its (public) methods. Why might you want to hide data in such a way? So you can delegate responsibility to the object, because it will handle the data better than you will from outside the object. You don't need objects for that. You can do that with data and functions - unless you insist upon the apple.eat() syntax instead of eat(apple) discussed in paragraphs 2-3.
NB. Putting state inside an object doesn't make it safe for concurrent modifications. But that's a whole 'nother discussion topic. In the "real world" I rarely need to use a mutable data field in an object. Fields are generally just other dependencies, e.g. database handles or other services.
I think I did a reasonable job of hitting "the core principles". It's not so much that they're "bad ideas", but rather, once you strip away the large, good majority of ideas which is available outside OOP (e.g. delegation of responsibility) you're just left with the bad ideas (e.g. inheritance) or ideas which have been executed better elsewhere (polymorphism, message passing.).
OOP is 'widespread' because it is frankly a very powerful (and obvious) way to encapsulate and organize information and function by breaking down said problems into digestible units or 'mini modules' if you will, that also happens to lend well to how humans interpret the world.
Polymorphism is a very powerful tool for adaption.
Far from 'problems at scale' - it's the complete opposite: well designed OOP is generally the best abstraction to use at scale, to the point wherein most of the world's most comprehensive APIs are in fact OOP.
Inheritance is definitely overused, and OOP is not ideal for many kinds of projects, but overall, it's successful because it's extremely useful.
It's 'mid level' Engineers, those who have discovered the foibles of OOP Orthodoxy, who 'develop their own ideas for the first time' who are the most ardent critics. Those who get past that see it for what it is, just a tool, very useful in many ways, not so much in others.
TypeScript has fundamentally better OO utility that Javascript, Dart was developed using OOP, Kotlin absolutely kept those ideas, etc. etc..
Obviously, maybe not the best for a lot of systems programming.
It's 100% here to stay, or at least an evolution of it.
Trait-based programming solves polymorphism much more elegantly as any type can adopt a behavior. These systems are going to replace the old paradigm.
For example I just added a data caching system where a generic DataCache is used by most data types, with a few more sophisticated caches for special needs implementing the same DataCache protocols, so they can all plug in to the same places wherever needed.
And a series of CacheRefresh objects that inherit base refresh functionality from a superclass, and just impose the their specific REST api calls. And everything is written as functional as possible, with limited state and parameter dependent methods.
It’s working great, any model that needs caching can have a data cache, and any UI that needs to prefetch data can have a CacheRefresh object for each type of data it’s dependent on. I’ve pretty much minimized boilerplate and redundant code this way.
So what am I doing wrong, or what could I be doing better?
You seem confident in this position - can you provide some resources for others to become more familiar with that philosophy, proofs against OOP, and/or alternative approaches to architecture?
If anything is pure OOP it's COM. And although it has a deserved reputation for being hard to start working with, and documentation these days is sparse; it's going full-steam ahead when you boot a Windows box.
That statement seems out of touch of the decades of OOP flogging that it took to get OOP support to be a staple of mainstream programming languages, so that it could be a common denominator.
Just a some three decades ago, anyone using OOP terminology was instantly stereotyped as an ivory tower academic.
I think its more complex then this. The simplest form of programming is procedural. OOP is a level of abstraction above it in terms of understanding. I think the catharsis of grokking OOP gives it the illusion of being better.
All we were ever taught was basic imperative programming, then OOP and then several years (!) of just OOP frameworks (Android, ASP.NET, Angular and the like). We never talked about functional programming, we never talked about software architecture in general (outside of those frameworks).
There was a subject where we explored "computer science fundamentals" like some algorithms and data structures and, among other things, logic constraint programming. But that subject was so small and unimportant to your grade that you could just sleep through it.
This is pretty vague. Is "school" here, like, a 4-year comp sci degree? A bootcamp? A 2-year diploma?
To the vast, vast majority of software developers, it's "just how you program" (most don't even know there's alternatives).
It's really hard to go in an organization where hundreds or thousands+ developers live or breath through OOP as the gold standard, and suggest to do it differently. Thus the status quo lives on.
I don't enjoy the functional languages out there, at all. I enjoy some functional concepts within an OOP language, but I would be fine with just a pure OOP language if I had to.
Then among the people who do know about it, an even smaller fraction learnt about it first, or in the same depth. Among those who did, very few learnt it in a practical way (Learning ML in college is unlikely to get someone to use FP to build production software, especially before ReasonML was a thing).
With all that, is it a stretch to think people don't use FP because they don't know about it? No, I don't think so. It could be 100% objectively superior in every way and people still wouldn't use it in those circumstances. And its' far from being "obviously" better.
Eventually I sat down and read what OOP actually was. I immediately realized that I'd never worked on a single object-oriented architecture despite a decade of working in object-oriented languages.
I can't stress this enough. Using an object-oriented language does not mean you are building an object-oriented system. If you cannot differentiate your classes from C structs, you are probably not building an object-oriented system. If you have functions that manipulate objects, rather than objects manipulating each other, then you are probably not building an object-oriented system.
This article seems to conflate these ideas in the same way. It seems to say that "the success of languages who happen to be OOP" somehow implies "OOP is still one of the dominant paradigms right now". I don't see any other explanation for that claim beyond this inference.
Based on all the systems I've worked on at various software companies (heavily weighted to SaaS), I would be legitimately surprised if it was true that "OOP is still one of the dominant paradigms right now."
edit: Decided not to explicitly recommend the Byte article[0]. It's good but doesn't go deep enough to get the nuances across unambiguously.
[0]https://archive.org/details/byte-magazine-1981-08/page/n75/m...
I think C would be 10x more useful language if it ditched include files and had "import" like python
I'm trying to imagine this, and I'm at a loss. How do you mean? The namespaced part of the import, where you can pick and choose what you get? Or the managed part of the import, where all your libraries live in a language-version-specific folder?
One of the great joys, to me of C, is it's insane flexibility. Include files are a hassle, but I don't feel they're something I've ever had to work around. I can't say the same for /usr/lib/pythonX.Y or in particular the way things like 'pip --user' work.
> I'm pretty sure a lot of the popularity of oop actually came from modularity
That's one area where C could be better, in my opinion. I don't need inheritance or friend classes or any of that, what I _really_ want is to namespace the methods that are meant to work on a single struct _with_ that struct itself.
Effectively, I would love to write my C structs the way C++ coders write the POD types.
To me this is the primary benefit (although the file mapping is convenient).
As to python... it is impossibly more flexible than C. I have done silly stuff like reading all the files in a directory, then i imported all the python files I found.
I think C is not very deep, but it is very well known.
> The real significant productivity advance we’ve had in programming has been from languages which manage memory for you automatically. It can be with reference counting or garbage collection; it can be Java, Lisp, Visual Basic (even 1.0), Smalltalk, or any of a number of scripting languages.
https://www.joelonsoftware.com/category/reading-lists/top-10...
(Grep for "Automatic Transmissions Win the Day")
Like you say pythons import is a different beast and it can run code at runtime when it comes across that statement. Some training is not clear on that. Like you point out import does not just import the file it runs the thing. If the file only contains def's then it effectively just defines a bunch of functions/objects and does nothing else But it can. C is not like that. It is more copy the whole file here and apply the current state of pre-processor rules.
* ability to reference other files in a manner other than copy/pasting
- allowing the compiler to understand when it should cache what it already knows, instead of having to set up and deal with precompiled headers for large projects
- ability to treat a header file as a single unit and not leak preprocessor defines
* treating many files as a single compilation unit, leaving LTO to only be needed when linking to a library
Immutability is more of a core FP concept, than an OOP one. I guess the point is the categorization of the language you're using doesn't necessarily commit you to programming in that paradigm.
I do wish Java had made `final` the default for fields and variables. Lombok's `@Value @With` takes away a lot of the pain though.
Object-oriented programming, fundamentally, is about associating code with the data it manipulates. Code + data = object. Two essential follow-ons:
* Encapsulation: Your object provides an interface composed of methods, without allowing callers to reach in and mess with the data inside except by calling those methods. This allows your implementation to evolve without breaking callers.
* Abstraction/polymorphism: Objects with different implementations can implement the same interface thus making them interchangeable. This enables code which operates on such objects to be reused across wildly different use cases.
These fundamentals exist in basically all large systems. Example: Linux file descriptors are objects. Different kinds of file descriptors (e.g. disk files vs. sockes) implement the same interface (syscalls, e.g. read/write), and you cannot reach directly into their implementation from userspace, which allows the kernel implementation to evolve over time. You really can't not use OOP in these scenarios.
The opposite of OOP is separating code from data. In anti-OOP, you declare your data structure completely transparently, without declaring any kind of "methods" that apply to it. Code modules interoperate by operating on the same underlying structure. This tends to lead to sclerosis as adding new features to the data structure without breaking existing code can be quite difficult.
My hot take: The philosophy of REST (though less often the actual implementation) is disturbingly anti-OOP.
I'd also like to know why you think REST is disturbingly anti-OOP. It does impose a separation between the implementation of a resource and its representation, right? So multiple implementations could have the same representation and the same verbs. So in that sense, it's like OOP, isn't it?
Looking it up, I think I was wrong about that. Early OOP did in fact have implementation inheritance.
I guess what I should have said is, OOP originally had three legs. One of them turns out to be bad but the other two seem fundamental to large-scale systems programming.
> I'd also like to know why you think REST is disturbingly anti-OOP.
So, this is pretty abstract, but REST philosophy seems to put a lot of emphasis on representations of data while discouraging communication of operations on the data. The way to operate on the data is to GET the representation, modify it, and then PUT it back -- not to POST a message saying "please perform operation F". I've heard several hardcore REST advocates specifically argue against communicating operations, deriding it as "RPC" (which I guess they see as derogatory?).
In practice I think most people only follow this philosophy when it makes a reasonable amount of sense and ignore it when it doesn't.
At a very high level, they can guide the conversation well. As soon as the boots hit the ground, though, the lines between subsections of a design are ridiculously arbitrary and not at all disconnected from each other in a meaningful way.
In physical systems, this can be blurred when you have more obviously consumable parts of an object. Think the brake pads of a bike. That said, the wheel of many bikes is also a consumable part of the braking system. Such that the question is less "where is the separation of braking from drive train" and more "what parts are easily removable from the bike?" And it is definitely the case that that question is not necessarily built up in a taxonomy, Though it is certainly usably described in a variety of them.
One could easily change the taxonomy from "wheel" and "brake pad" to "spinning surface" and "stopping surface." And if you want to construct a bicycle by composition, you know that in order to implement brake() you need two items which implement SpinningSurface and StoppingSurface. The SpinningSurface could easily be of type WheelRim, but it could also be of type BrakeDisc. And in both cases the StoppingSurface is of type BrakePad with the difference in how BrakePad is applied to SpinningSurface.
And with this taxonomy you could also allow users to use Shoes, WaterBottles, Wrenches, and a whole host of other objects as StoppingSurfaces.
So the problem isn't with trying to encode anything with types, the problem is that people try to encode everything with types. You have to pick your battles, and you have to devise your taxonomy such that you can make meaningful abstractions. That remains an art form.
I tried to make it clear that I do find high level taxonomies nice. Just the further you zoom in, the less useful a strict adherence to that will be.
What the heck is "top-down programming"? I've been writing code for close to 20 years and this is the first time I've encountered this term.
Google reveals results like this one [0], that explain it as "essentially the breaking down of a system to gain insight into the sub-systems that make it up."
So, in other words, literally any kind of programming? All programming paradigms are about building abstractions to avoid repeatedly dealing with low-level details.
Is this really a thing that people talk about?
[0] https://dzone.com/articles/how-does-top-down-programming-wor...
People hate bloat, complicated ways of doing simple things, and AbstractFactoryAdapterFactoryAdapterFactories. These abominations got built in Java, an OO language.
Toss out all the religion and all you have are a few useful programming ideas. I was around when a popular "software development tool" of the day was a template. (No, not what you are thinking. I mean, a piece of plastic with shapes cut out of it.) You could use to draw flowcharts. Then, "structured programming" came along, basically the OO of its day. Structured programming meant no GOTOs. Instead, use the things that GOTOs usually implement: while loops, if/then, if/then/else. Keep functions to no more than "a page" (i.e., entirely visible on an old 24x80 screen).
Structured programming was uncontroversial. People recognized progress and adapted it. This happened when there were very, very few independent software companies, and there was a miniscule market of software developers. I can see though, how it could have gone wrong if there were companies intent on exploiting structured programming by turning it into a complicated fad requiring salesmen, consultants, trainers, and all the other profit-making paraphenalia.
Though I have written telecoms billing systems in Fortran (and some Pl1/G) and worked on Fortran simulations of Breeder reactors n my Time - so I guess I am a Real programmer Tm
Its about using the tools you have for the right job some times oop is right some times not
What people really hate is "enterprise OOP" and its related ecosystem.
It's like Agile. Agile is fine. But people hate "enterprise Agile" and the whole ecosystem around it.
I mean sure, this is mostly true of Go more than most other languages though. I didn't mean to pick on Java alone, C# which is a language I love has this similar problem, though they seem to be heading slowly towards a multi-paradigm language, though the emphasis on OOP is still there, it doesn't feel as restrictive as Java.
Heck, even Kotlin seems to be getting rid of a lot of what I call the ceremony of Java whilst still producing equivalent bytecode (I can only imagine most of it is just syntatic sugar).
Plus the multi-paradigm nature means there’s less consistency with 3rd party libraries, and they’re usually OO in structure, which obviously annoys me to no end.
If the only reason is because the language doesn't permit otherwise (like Java) then it's essentially nothing but extra boilerplate. When you write a lot of code, this all adds up. Inevitably, over time, folk will grumble. There are simpler ways to express such things in other languages.
Sometimes less is more.
Which OOP are we talking about?
That ideas's been nagging at me lately. In his paper, The Early History of Smalltalk, Alan Kay wrote, "doing encapsulation right is a commitment not just to abstraction of state, but to eliminate state oriented metaphors from programming."
Basically all code I've ever seen in OOP languages is incredibly stateful. And it makes a lot of reuse difficult, because that stateful behavior makes it difficult to confidently compose things from smaller pieces. That stateful behavior means that the class's internals aren't truly encapsulated. You still need to understand those details about how its state changes to interact with it successfully, even if you can't observe the state directly.
That syndrome can lead to over-abstraction and tight coupling of objects.
Java offers only one mechanism that gets abused for everything. Contrast with C++ (or Common Lisp, Haskell, Python) that support numerous abstractions, so that the best may be chosen.
So, people don't really hate OOP. They hate people who learned to program on Java, and still think that way.
It's difficult until you also consider conlangs like Kēlen[2] which also attempt to build a kingdom of nouns. OOP is a hammer that makes everything a nail for the same reason Kēlen is a conlang rather than a humlang. There is a certain element of hoop-jumping that takes place when a language doesn't have the grammar to express things naturally.
[1] https://steve-yegge.blogspot.com/2006/03/execution-in-kingdo...
However, if you turn your back on OOP entirely, where does that leave you? You have to go down the functional programming route.
FP has it's own problems. Ever see a large FP-style JS program? It resembles procedural code. Functions strewn around the codebase with no hierarchy or compartmentalization. Anything can (and will) call anything. You pipe data along from function to function, but you quickly find that the chunks of data that you're sending keep... growing... because you can't keep the entire codebase in your head, and you can't remember that variable X is equivalent to Y in all cases, so you just pass Y along also.
It is this superficial understanding of OOP that led to a somewhat bad reputation. At least in the form "getX" and "setX" it would be more of a data structure with mostly useless methods around the fields. If a programmer is able to set each and every field from the outside through a setter, there is no encapsulation at all. To have objects that deserve this name, a method should be more like a "transaction" on the object, so related fields should be changed in one shot.
Apart from that, I don't think it is useful to think in separate camps (OOP vs FP) here, since both approaches are complementary in many cases. It is not like you have to decide for the one or another theses days, since most common languages support OOP and FP style.
I've always liked Smalltalk's philosophy on many things and a key feature of its idea of OO is dynamism and 'late binding of all things'. Popular OO languages like Ruby or Python borrow heavily from Smalltalk and they're great to use and very popular.
It's the combination of static typing and OO I think that leaves a bad taste when it comes to OOP, and I think that's also reflected in newer languages. A lot of younger statically typed languages like Rust or Go seem to have ditched the OO paradigm, and embraced FP.
public class Main {
public static void main(String[] args) {
System.out.println("This will be printed");
}
}
>java Main
Also, there is no way you could get things done, without spending a year studying what each of
Class, static, void, System, args, etc
meant.
It's hardly surprising there will be a number of people. who realise that that's neither the only nor the most efficient hammer to drive in all types of nails.-- Edsger Dijkstra (1930-2002)
Some people like flexibility, but most people just like having a detailed set of rules to follow.
I think this is the reason behind a lot of trends in our industry: GitFlow, Scrum, Kanban, TDD, even FP.
The ones that get complained about, and the ones that don't get used.
Inheritance is really just about writing better namespace and domain / contexts of your code.
Polymorphism is really only ever an "issue" I've seen when dealing with strong typed langs and all the langs where it has become an issue they provide interfaces to aid in Polymorphism.
I don't think anything about what was listed is #1 exclusive to OOP and 2 doest not already have best practices to address in OOP and other langs.
Everything that was written about was not about the problems they solved but the patterns used to address the problems. I think that makes it too subjective to be constructive.
I will say though there is nothing fun about mocking complex state in tests for a rails app let alone if that state is shared or easily mutated.
He was trying to answer why functional programming isn't mainstream but the opposite is what we're posing here and I think it's for many of the same reasons.
Network effects: a lot of these languages were mainstream earlier on and got buy in from a lot of folks who are invested in their continued adoption and success.
Platform exclusivity: some companies push their own language ecosystems on their platforms and those languages are often OOP/multi-paradigm languages.
Specifically to OOP we have to ask why is the particular style of C++/Java OOP the norm? Why didn't Eiffel, Smalltalk, or Self reach the same market?
[0] https://www.youtube.com/watch?v=QyJZzq0v7Z4
edit: forgot the link -- oops.
It ends with talking about how loved Scala is as a language, while most of the Scala code I've seen is more OOP than FP.
Rather, people need buzzwords do dress up their non-thoughts on software architecture, and no new ones supplanted OOP's so they are still in use.
Maybe someday "container" will replace "object" :/.
The premise of the question is false.
There are a few people who hate OOP, and a larger numbers who hate (or at least dislike) the conditions in the period of unquestioned OOP hegemony when that square peg had to be shoved in every available round hole.
"OOP is just a mental model. Deep down everything is made of bits. The church of OOP has failed but if something looks like a duck, walks like a duck and talks like a duck it probably is useful to make a duck class. We're now down to fighting for nuances. You can do most things with OOP or without OOP but each path has some upsides and downsides and most of the time it's good to use some things it provides where it makes sense and not get too religious about it. The great architect has the foresight on how the code will be used in five years and design it accordingly."
There is something universal in our understanding of temporal logic that makes objects changing over time an intuitive model for a computer's internal state.
But that is exactly what a computer does: changes state over time. Languages ignoring that fact are prisoners of their own niche and will never be as popular as those which don't ignore the hardware.
But I have never really understood the desire to move to pure functional programming for the following reason:
I always end up with a group of functions that are repeatedly passing around the same variables. It might only be two or three or four variables, but quite often it seems that I can make the code less noisy by assuming that the state is attached to the instance already and so it doesn't constantly need to get passed around.
And I know someone is going to say I am just not factoring things properly, but after a number of years of repeating that experience, I don't buy that anymore.
The premise of the question "If everyone hates it..." is invalid.
Wait, what?
Maybe not everyone hates it.
Like a lot of things, it's a matter of culture in academics or elsewhere.
This article doesn't talk about the drawbacks of OOP, one is the tendency of programmers to make things abstract when it's unnecessary. And it doesn't even try to explain why people hate it.
In france we call an regular subject point a "maronnier", which is tree that gives fruits every year, fruits everybody likes.
Say you have a string, in Java, Python or whatever. It it more natural to uppercase it in an oop style mystring.upper() or a functional style upper(mystring)? Personally I think it makes things more manageable to keep the data and functionality together.
I know almost nothing about "OOP', but I was under the impression this was bad OOP?
In DB oriented programming, instead of god objects that store global state for everything under the sun, there is a god database that stores global state for everything under the sun.
Historically, software engineering has been a cat and mouse game of referencing global state, finding some clever way of hiding it, and then finding an even more clever way of referencing it again.
Lather - rinse - repeat!
For more info, see the docs for the Haskell extension: https://wiki.haskell.org/Existential_type
Also, it isn’t like OOP is one programming paradigm. It is several that make up one region of a landscape. And within each paradigm there is room for styles.
Finally, if X is better: then ask instead how you (yes, you) will make other people use, and like, X. People change languages because they find something that helps them achieve goals.
Also: “what has become our past, forever remains so”
— Dijkstra, on trendy 90s/millennium OOP in academia.
1. Heavy use of reference semantics prevents local reasoning about code. 2. Inheritance is really brittle. A subclass can break superclass invariants.
I don't think anyone really contests either of those... it's just a matter of how much you can put up with.
This is a good one if you extend it a bit further: they are concerned with the proper taxonomy and it usually happens to be wrong.
Because some problems still nails?
Having state in a closure does not imply that it's OOP, so I'd really like to see those frameworks for reference.
- still the main target in interviews (GoF pattern much) ?
I am using FP together with OOP when it makes sense, with great results. Both approaches have their advantages in specific contexts.
Abstraction and Encapsulation? Every programming language lets you do that with functions (or some other way).
Inheritance? Even OOP die-hards favor interfaces over inheritance.
Polymorphism? Interfaces (like in Go).
What's left to distinguish OOP with? The bad choices that Java made, like not allowing standalone functions i.e. Execution in the Kingdom of Nouns. That's what everyone hates on when they say they hate OOP, they hate Java's style of OOP.
When you look at the 'virtues' of OOP it all falls apart because other non-OOP language achieve the same thing without being Java.
>Significant object-oriented languages include Java, C++, C#, Python, R, PHP, Visual Basic.NET, JavaScript, Ruby, Perl, Object Pascal, Objective-C, Dart, Swift, Scala, Kotlin, Common Lisp, MATLAB, and Smalltalk.
So pretty much every popular language out there. Doesn't look so hated. :)
Cake should inherit Food or Pastry or something and Eat should be made a generic that accepts a base class
/sarcasm
1. A → B
2. ¬B
∴ ¬AHere are some things that OOP does not give you:
* Is your state normalized, i.e. saved only in one place? You do not know.
* Is your execution predictable? Parent to child? And how do you do it when it's reversed.
* What should be public and modifiable and what should be intermediate state internal to the object. And should intermediate computed values be stored next to values determining the true state of your application? (even though there are "public" and "private" modifiers it is quiet difficult to determine what is truly public and cannot be modified through some method. This makes it more difficult to understand what the state of your application truly is and what are intermediate convenience values).
* Are there limitations on passing state around? Or can large chunks of state be passed to multiple actors in the form of classes who change it concurrently or might store it for later use?
* How much state should be in a single class? In other words: how many classes can a class encapsulate and how complex could those classes be?
* Should something that has no state be an object or just a function (in some languages you are not given the option at true, but can't say that it's awesome).
* Should you be allowed to use event buses and how to prevent spaghettification? (cause events really are akin modern goto statements).
* etc.
Basically the ability to compose the state, type and methods is so wildly open-ended that almost always what I see is just an ever expanding convoluted bloat of state spread ts chaotically that it become extremely difficult to see what the state of your application is at any moment. Everybody has their own idea of what an object _is_, what should be an object and how they should come together. And that is for every developer on the team. So you can follow the absolute best of OOP practices and still end up with a mess.
Let's look at a counter-example. It is not a system that claims to be universally usable but that is the point. I'll use the, quiet banal, example of React. Yes, it is a framework, and in a way it does have objects, but really it borrows heavily from functional programming in the sense that it says that state is king and the single most important thing in your program. That you _must_ have strong constraints as to how your state is created, organized and modified. (In contrast to a class, which is state that you can pass around as much as you want and the whole codebase could modify it at will).
* The application is always a predictable tree of dependencies.
* State is either stored separately altogether (using a state-store such as redux, mobx, etc.) or bound to a particular element in the tree hierarchy.
* State only flows down the tree, ideally immutably.
* A component (unlike a class) cannot modify state of anything outside of itself.
* Only "has-a" relationships are allowed - no polymorphism.
* Only event can be passed up.
* State is essentially a collection of easily inspectable primitives. Meaning that even though a component can _contain_ another component a class is not a valid member of component state.
While a system like this could be built using OOP primitives (classes). Nothing about OOP suggests this system. Yes, you can build it, but can build something absolutely unrelated. And, really, it enforces things that are the antithesis of many things that "proper OOP" espouses.
Perhaps the main thing of any system is to create a predictable and well-structured relationship between elements of state. I think that wonderful examples of the basis of such a system are Go and Rust. To be honest, I barely know the languages, but from what I see is that they make _type_ the most central element of the language. If you have your types well-defined and be separate from how the types are used you are already suggesting many things that could prevent state-sprawl. A struct defines the basic primitive around which your program is based.
* Struct has no private intermediately computed values. If you do not want to recompute something - memoize, do not bloat the state with random data that is inseparable from you base state.
* Structs provide a very predictable "has-a" top-down dependency between state
* No inheritance, so composition is enforced.
* Keeping types and functions that operate on those types makes it very explicit what a function does - is it a method or is it a function?
Scala was invented to merge OOP and FP.
The article is nonsense. It offers no alternative and then wonders why the thing everyone uses is still popular.
In practice most OOP code will violate some functional stuff.
There is no reason you can't do this in C# or Java.