9 ms·
>The thing you need to look at if you’re using say, a dynamic language, or object oriented design, is that in the long term, what is the language and mindset of
by gambler 8y ago
>The thing you need to look at if you’re using say, a dynamic language, or object oriented design, is that in the long term, what is the language and mindset of “objects” with dynamic dispatch providing you apart from an endless stream of bugs that seem to keep reoccurring everytime you try an evolve the software to introduce a new requirement?
I am sick and tired of the arrogant, willfully ignorant developers touting their FP horn and bashing OOP without any qualifiers. This is getting as annoying as Java people posting their design pattern nonsense as if it was something good.
If you know what a monad is, you should also know the founding ideas behind OOP.
http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay_oop_en http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay...
The ideas make sense. Moreover, Kay has an amazing track record of saying unpopular things and being proven right in the long run. If you spend some time looking into it, you should see that his high-level intuitions about software architecture are proving to be correct, despite many of his critics. A lot of hyped-up modern technologies are implicit, ad-hoc, overly complex implementations of OOP ideas done without realizing they are such. The whole IT industry would be far better off if people took time to look into and understand the original ideas behind OOP.
1. OOP is a higher-level paradigm than FP, so people comparing them directly usually are missing the point to begin with. OOP systems can be implemented in functional languages or use functional-flavored components.
2. It is beneficial to model algorithms without using state. FP is very good that that. (Boring but practical example: LINQ vs loops and variables in C#. Functional LINQ pretty much always "wins", just like Streams always win in Java.) However, large-scale systems almost always have state. If you do not have some wise approach for handling it, your designs will have issues at system level. OOP is one such approach and at that level its ideas have a lot of value.
I'll edit this post later to add a few more points.
- thraway-burnout 8y agoThis is a bit like the "Islam is a religion of peace" discourse. I'm sure it is, but: OOP as actually implemented and found in the wild isn't about Smalltalk or message passing. It's about transforming functions into methods by unnecessarily wrapping behaviour in classes, as an example of cargo-cult programming. OOP the idea is great. How do you actually find it in the world?
- depressed 8y agoIf functional programming were implemented as widely and abused as much as OOP is, would it really fare any better?
- slx26 8y agoexactly, I feel the same way. OOP is often criticised from functional programming, but also from data-driven programming, for example. You never hear functional programming advocates criticise data-driven programming. The use cases are so different that it wouldn't make sense. To use OOP properly is probably as complicated as doing functional programming or data-driven programming properly. The "problem" is that the learning curve is much less steep and the use-cases more extense, so obviously there's a lot more people misusing it.
- blattimwind 8y agoI've seen data-driven code and it is full of OOP. Those are hardly orthogonal concepts. Arguably DD (on the pedal to the metal C/C++ level) doesn't quite match the OOP choir in terms of looks.
- slx26 8y agoI totally agree, and I believe any serious programmer should have at least some basic knowledge of the three "paradigms", as the core concepts are relevant in all cases, and there are many techniques that can be applied in different "paradigms". I didn't start talking about it in order to keep the comment short, but maybe it was a bit confusing.
- ummonk 8y agoYou can already see examples of this. Take callback hell. Opaque callbacks are the functional equivalent of goto statements. Also, many functional programmers, particularly Haskell programmers, seem not to care about readability and maintainability. They're focused on maximizing their own productivity as an individual coder, and writing cool concise and abstracted code that might not actually be easy for another engineer to understand and modify. The difference though is that good functional programming is still quite common whereas good object oriented programming seems to be rare (the one exception being microservices).
- Jtsummers 8y ago> 1. OOP is a higher-level paradigm than FP, so people comparing them directly usually are missing the point to begin with. [emphasis added] How so?
- l_t 8y agoNot the OP, but I might have some context. I think of OOP as a message passing paradigm. It's concerned with how messages are passed from one part of the system to another. It is not particularly concerned with how those messages are implemented under the hood. In that sense it's a higher level paradigm because OOP is all about building abstractions ("objects") and defining how they communicate, rather than wiring code together directly. FP doesn't really have anything to say about how you design your abstractions, just how you implement them in code.
- Jtsummers 8y agoWhen viewed that way, you're not dealing with most mainstream OO languages anymore. But it is the intent of the originators of OO and I prefer the same view. Especially because at that point it becomes orthogonal to imperative/functional approaches. Message passing can be used with a functional language (Erlang) or an imperative language (Go) to great effect. It can also be added onto (as a library) most other languages. However, I want to know if the original author meant it that way. And I still don't see how message passing is a higher level paradigm than functional programming. It's an orthogonal paradigm, neither subsumes the other, and both benefit when used with the other.
- dual_basis 8y agoWhere can I learn more about this perspective on OOP? I would really like to understand it in a way which is orthogonal to FP. In particular, do you think this perspective allows you to write better code in "multi-paradigm" languages that claim to support both FP and OOP? (I'm specifically thinking of Scala and OCaml here.) I have always felt that languages that try to do both end up being worse as a result, but maybe if I could understand the two concepts in orthogonal perspectives then I could make it work.
- pacala 8y agoExactly right. "OOP" is a system design paradigm. Useful for the 5% of the time one is concerned with big picture system design, and counterproductive for the 95% of the time one is writing mundane functions pertaining to their business domain. Alas, "OOP" was/is sold as a solution for everything computing, including the 95% of the time it is not a good fit. I call that track record "abysmal", your mileage may vary.
- ljw1001 8y ago> "OOP" was/is sold as a solution for everything computing, including the 95% of the time it is not a good fit. I call that track record "abysmal", your mileage may vary. In terms of real programs in the real world, OOP in the form of Java/C++/C# is by far the most successful programming paradigm ever. It's sort of amazing that anyone would call it's track record 'abysmal'
- pacala 8y agoPolymorphic modules are a necessity for system design. To be used sparingly. Turns out that Java/C++/C# provide a mechanism for polymorphic modules at language level. Beyond that, failures all around. On top of my head: * The insistence of designing systems fragmented in tiny state machines instead of systems processing immutable values passed around wholly and processed by pure functions. In the UI domain we finally got back to our senses with React. * The insistence that values do not exist, but rather objects = data + code. Leading to brittle abominations like CORBA, agents, etc. For distributed systems, a humble RPC passing values [NOT objects] back and forth is infinitely more valuable. * The insistence that inheritance is a useful design mechanism, leading to highly coupled codebases. Also, a prime cause for object-relational impedance mismatch. * The insistence that one should overengineer code for extension without modification at every turn. How about just write the simplest version of the code for today, and refactor it if new requirements pop up. * The insistence on messaging as fire-and-forget [aka goto] instead of structured function calls. Decades after we've learned why goto-oriented programming is a poor idea. * The insistence on overusing polymorphism to mock everything in testing. Making it hard to trace how the codebase actually operates, and making it expensive to change the codebase because tests and code are tightly coupled. * The insistence on overusing polymorphism for all type-based dispatch. Try writing a compiler in a purist OOP style, with a visitor for every type-based switch. Maybe it works in Smalltalk, 'cause in Java/C++/C# it gets boilerplaty really fast. Or even better, "encapsulate" your AST data into "objects hiding their internals" and do all type-based dispatch using vanilla polymorphism. Nothing screams "fun" like wading through tens of files to piece together what should have been a single switch block.
- agsamek 8y agoTo add more specific examples. If you want to understand OOP idea do not think about Java/C# classes and inheritance. Think about OS processes/IPC or microservices. These are Objects. This is the basic idea behind OOP. Getter/setter is the main anti-pattern of OOP design.
- dpc_pw 8y agoPersonally, I call that "Actors", not "Objects". In my experience OOP in practice means: objects, classes, inheritance, class hierarchies, despite the original intention (think Smalltalk-like).
- int_19h 8y agoBy this definition, neither Simula nor Smalltalk were object-oriented, which doesn't make much sense to me.
- beders 8y agoOOP is great if all you are doing is OO and if your solution to a problem is running a simulation (what OOP was invented for). But you are not staying in your pure OO-world nowadays. There's always the boundary issue where you are giving up your careful encapsulation and where state needs to be transferred instead of being hidden away in some object (like exporting to JSON). Poof, your encapsulation is gone. Furthermore, may OOP languages don't deal with ownership at all. If I'm a constructor and someone passes me an object A or worse, a list of As. Can I hold onto that list? Should I make a shallow copy? Should I make a deep copy, because I need the A objects in the state they are currently in? What if I have to work with 3rd party libraries? What assumptions do they make about that? Can I call methods on objects from multiple threads? I need to rely on the documentation to figure that out or provide synchronization myself just to make sure I'm not breaking things. Also, it is no accident that refactoring tools have become so popular in the OO world. If you need to design OO with 'change' in mind, you need to employ lots and lots patterns that make your code looks like new FactoryBuilderPatternVisitorImpl(). But with refactoring, hey, I can easily change my classes thanks to my IDE, yay! Too bad if someone then passes me data that only fits the old classes and too bad if consumers of my library are getting nasty surprises. It is with everything in software: use the appropriate tool for the job.
- 0815test 8y ago> OOP is great if all you are doing is OO and if your solution to a problem is running a simulation (what OOP was invented for). And even for simulation-like code (or really any other case of "very-high-level" code featuring "object"-like entities linked by complex, non-trivial relationships) ECS systems work a lot better than plain old OOP, while preserving the wide variety of advantages that you rightly point out. Especially since ECS works as a reasonably-thin layer over the usual sort of data-oriented programming.
- gambler 8y agoSorry, but you're just validating my stereotype of a typical OOP critic. OOP != Java. >OOP is great if all you are doing is OO and if your solution to a problem is running a simulation (what OOP was invented for). Most problems most programmers solve are simulation in some sense. Including DevOps. I wish larger number of people realized this. Things would become much simpler. The problem with class-oriented languages like Java is precisely that they are horrible for making simulations. Been there, done that. >There's always the boundary issue where you are giving up your careful encapsulation and where state needs to be transferred instead of being hidden away in some object (like exporting to JSON). Poof, your encapsulation is gone. Solving boundary issues is what OOP was designed for. Like, that's literally the original goal of the whole concept, as explained by Alan Kay many, many times. You were able to send objects over the wire in Smalltalk in the 70s. Every time you open a webpage with JavaScript you're performing an ad-hoc reenactment of the same idea. The fat that this idea is implemented badly on the web doesn't mean this is a bad idea. >Furthermore, may OOP languages don't deal with ownership at all. If I'm a constructor and someone passes me an object A or worse, a list of As. Can I hold onto that list? Should I make a shallow copy? Should I make a deep copy, because I need the A objects in the state they are currently in? This problem has been solved in 1978. http://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TR-205.pdf http://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TR-20... >Can I call methods on objects from multiple threads? I need to rely on the documentation to figure that out or provide synchronization myself just to make sure I'm not breaking things. See the paper above. BTW, guess how I found it? Alan Kay's talks. >Too bad if someone then passes me data that only fits the old classes and too bad if consumers of my library are getting nasty surprises. Again, getting rid of "raw data" was one of the core motivations behind OOP. See the email above.
- l_t 8y agoI've gotten a new appreciation for OOP (and TDD) after reading "Growing Object-Oriented Programs Guided By Tests." It's made me start thinking of programs more as multicellular organisms, or communities, where each part is responsible for a particular task. I think this is the core genius of OOP. It's not about classes or (Java) interfaces, it's about programs being communities of cohesive individuals with well-defined communication protocols. edit to add: I think another key difference is in increasing the level of abstraction that you think about your program. You want to build a layer where you just say what should happen (the "declarative layer"), and keep that separate from the idea of how it should happen (the "implementation layer").
- naasking 8y ago> 1. OOP is a higher-level paradigm than FP, so people comparing them directly usually are missing the point to begin with. OOP systems can be implemented in functional languages or use functional-flavored components. It's not higher-level, it just allows different types of abstraction. OOP is about procedural abstraction, ie. a set of procedures permits you to add new types, FP is about data abstraction, ie. a given set of data types permits you to add new procedures. Most OOP languages are not pure OOP, so they permit some data abstraction as well, and FP languages with good module systems also permit procedural abstraction.
- joe_the_user 8y agoOOP definitely allows you to add both data abstraction and procedure abstraction. FP is opinionated concerning how one should abstract and OOP is fundamentally less opinionated - for good or ill (that is pretty much the debate).
- naasking 8y ago> OOP definitely allows you to add both data abstraction and procedure abstraction. No it doesn't, not pure, typed OOP [1]. Unless you introduce dynamic types, then neither is more opinionated because you can just cast or dispatch at whim. [1] https://www.cs.utexas.edu/~wcook/Drafts/2009/essay.pdf https://www.cs.utexas.edu/~wcook/Drafts/2009/essay.pdf
- joe_the_user 8y agoIn the vast majority of OOP language, the object allows one to do virtually anything behind the scenes with a bit of construction (plus of course functional programming is opinionated. There are a whole variety of definitely bad practices an FP programmer will point to as being disallowed by the FP). See: "Closures And Objects Are Equivalent" etc. http://wiki.c2.com/?ClosuresAndObjectsAreEquivalent http://wiki.c2.com/?ClosuresAndObjectsAreEquivalent And https://stackoverflow.com/questions/2497801/closures-are-poor-mans-objects-and-vice-versa-what-does-this-mean https://stackoverflow.com/questions/2497801/closures-are-poo...
- chalst 8y agoI agree that the "whole IT industry would be far better off if people took time to look into and understand the original ideas behind OOP". I also agree that OOP can be great at modelling system-level state. And about the compatibility between OO and FP, coming from a pure-FP background, I became very impressed by the advantages of combining FP with OO when I started to learn an ancestor of OCaml in the late 90s. But... dynamic dispatch is a source of errors when it is very often possible to get the benefits via type classes, giving strong compile-time guarantees. It's possible to understand "OOP is a higher-level paradigm than FP" in more than one way. I see no fundamental reason why you can't model the top-level interactions of a system using FP. And if state has been wrapped in a monad, you can chase the state through the codebase looking at the typeclasses inferred.
- gambler 8y agoToo late for editing. Here is what I wanted to add: Low-level code correctness is overrated. With some experience it's trivial to achieve even in a crappy language like Java. Nothing except horrible syntax stops you from writing "functional" code in Java (and even that became easier in Java 8). This is what I and all sensible engineers I know are doing. In my experience, this "weak" version of FP plus a few tests is enough to virtually eliminate low-level coding bugs. You can still get some surprising behaviors from 3d-party libraries and stronger FP can help with that a bit, but it's nowhere near as drastic of an improvement as many people present. There are two big classes of errors I do often see in real life. 1. Spec omissions aka systems Broken As Designed. Your system works the way you expect it to work, but produces results users did not anticipate. 2. Emergent problems. Like someone shutting down your service for a day, causing queue backup, causing a huge batch of data being sent to vendor when the service is back online, causing vendor to throttle you, causing all other jobs being delayed. #1 seems to be mostly a matter of experience and knowing when to show people some diagrams. OOP and especially agent-oriented programming can actually help you when reasoning about #2.
- dual_basis 8y agoI don't have the experience to assess your comments regarding the classes of errors you have seen in practice, but I'm interested in the other argument I have often heard of in favor of FP, that it is substantially better for concurrent coding.
- Karrot_Kream 8y agoProblems like #2 are all about emergent behavior problems, so thinking through 2nd and 3rd order effects. Isolating things in stateless functional units and using higher level constructs doesn't actually gift the engineer with the foresight to think through these problems. I agree with GP, these problems are orthogonal from using FP or OOP.
- toast0 8y agoNot having shared memory eliminates a whole host of popular errors in concurrent languages; handling messaging explicitly as messaging forces an ordering on events, which is nice too. Of course, you can still deadlock yourself; and read-modify-write can still be done in a racy fashion. Emergent properties of a system are still hard to reason about, but individual processes should be easy to reason about.
- balfirevic 8y agoThere was a big discussion on HN recently about what exactly the message-passing-oop is, with no apparent consensus: https://news.ycombinator.com/item?id=19416511 https://news.ycombinator.com/item?id=19416511 I don't have a strong opinion on the topic of OOP vs FP, but it's worth keeping in mind that people mean different things when they say OOP. Furthermore (and more importantly for this particular discussion), it also appears that people mean different things even when they specify they mean alan-kay/message-passing variant of OOP. For many, it's something like Smalltalk and Ruby, with their very late binding and ability for objects to respond to messages even without matching methods. Others find Erlang and Elixir to be good embodiment of Alan Kay's vision. And the third groups seems to define it as "kind of like how bacteria communicate, and kind of like microservices", which is really too fuzzy for meaningful discussion. In your link, Alan says: "OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things." That is... quite vague.
- sevensor 8y ago> OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things. It can be done in Smalltalk and in LISP. There are possibly other systems in which this is possible, but I'm not aware of them. This seems to be Kay's key point. The description of object orientation is very unlike any modern system I've used, and he mentions elsewhere that even modern Smalltalks fail to live up to it. My problem with this vision of OOP is that it would seem to take a great deal more support from the programming environment to make it work, compared to FP. Or perhaps the problem is that this "true" OOP is so much harder to grasp that it's impossible for me to approximate it in another language, where with FP I can obtain some of the benefits just by writing pure functions in an otherwise imperative language.
- scroot 8y ago> My problem with this vision of OOP is that it would seem to take a great deal more support from the programming environment to make it work, compared to FP One way to think about this is that there isn't a difference between your programming environment and the rest of your computing environment. There are no real "applications". There are just message sends and objects floating around. This is what Smalltalk was/is like.
- loup-vaillant 8y ago> If you know what a monad is, you should also know the founding ideas behind OOP. You know full well that those founding ideas are mostly irrelevant to what most people mean by "OOP" nowadays. "OOP" right now is C++, Java, C#, Python… What Alan Kay was talking about is now called the "actor model", of which the most prominent champion is Erlang, which sells itself as a functional language. Different times, different terms. Which is why I can say with a straight face that OOP sucks and Alan Kay is brilliant.
- tathougies 8y agoState handling in FP is a long solved problem. Actually, state handling in pure functional languages is often better and more easily understood than the wild wild west of imperative languages. I would probably try to understand the field more before offering criticism
- dragonwriter 8y ago> However, large-scale systems almost always have state Managing state is a central part of what FP systems do; a normal Haskell program is, in a sense, a function that returns an imperative program for handling stateful interaction. The stateful and stateless parts are clearly distinguished so that the problems associated with state can be managed more effectively and don't make it hard to reason about parts of the program that have no reason to be state-sensitive. While the mechanisms are different, that separation seems broadly the point of most pure FP systems and many impure ones.
- pubby 8y agoWriting stateful code in Haskell is super clunky though. State monads and lens? - Yuck! I'd take an OO language over that mess any day.
- cannabis_sam 8y agoState Monads and lens are just libraries though, and only one of many ways to deal with stateful code in Haskell. OOP, on the other hand, is clunky as a concept...
- ljw1001 8y ago> Java people posting their design pattern nonsense as if it was something good. Design patterns were developed by C++ and Smalltalk people.