4 ms·
>When the mutable state is essential (like in my example for a file stream object) that’s not a problem at all, quite the opposite, it allows to expose idiomati
by leafboi 6y ago
>When the mutable state is essential (like in my example for a file stream object) that’s not a problem at all, quite the opposite, it allows to expose idiomatic API from a library/module, while hiding implementation details from consumers.
Yes, When mutable state is essential pure FP cannot help you. However much of FP styled languages / frameworks are designed to segregate mutable state away from your awareness as much as possible. See React or Haskell.
Even so, like I illustrated in the Jungle banana gorilla example. When you have mutable state, it is better to deal with it without using OOP. Take a look at that example again, see how the procedural function is better than the OOP method.
>Your method is bad if the code is performance critical, your call stack is twice deeper than 1 or 2. Even ignoring performance, deep stacks complicate debugging, all debuggers show call stacks, they may also be visible in other places like crash dumps, exception traces, or logs
We can talk about the qualitative benefits of each but I'm sure you'll agree from a language/API perspective... My method is the best method in terms of reusability. If the focus of your code is reusability and modularity FP is the best way to go. However you are right that there is inevitably a performance cost. Computers are essentially machines that rely on mutability and have memory boundaries. Any functional abstraction implementation on top of such a machine will not be a zero cost abstraction. We're in agreement here. However you will note that for most modern programming the performance cost is no longer a factor that matters. Either computers are way too fast and make the performance cost negligible or there are bottlenecks in other parts of the system that make the performance gain negligible.
Games and Databases are two examples where FP may not be the most appropriate paradigm due to the performance critical nature of the areas.
>I don’t particularly want to, but for 99% of real-world software dealing with mutable state is essential part of the problem.
Yeah A lot of FP languages have abstractions that help you get around this. See Haskell or React, look up FRP and the IO Monad. Not trivial research subjects.
Look think about it this way. OOP promotes shared state and mutable state in places where it isn't necessary. FP forces you to use a minimum amount of shared as possible and segregates that away from your program. There are essentially two types of functions:
functionThatGetsDataFromIOOrChangesState()
functionThatTakesInputANdHasAnOutput()
FP has abstractions that highly segregates these two types of functions. OOP has facilities that integrates all these functions together into arbitrary groups called objects. The purpose of a class is to hold mutable state and integrate side effects with logic. If your class does not hold mutable state then essentially it's just a class repurposed as a namespace with syntactic sugar around the object_verb(object) semantics.
If you are writing a low level program that deals with a lot of mutable state or IO, FP can still operate in this arena via the abstractions but if performance is super critical then probably don't use FP for this stuff. Still, better than OOP for mutable stuff is just a straight up procedural paradigm as I showed you in the banana jungle gorilla example.
IO and mutable state needs to be separate from Logic in order to promote reusability. This is the key area where OOP fails. Procedural programming can achieve this separation while Functional Programming Forces you to achieve this separation.
FP has its downsides and upsides, it is however the most reusable and modular paradigm that currently exists. If modularity and elegance is your objective nothing I know of beats it.
As for OOP, when you bring in procedural programming into the picture, OOP no longer has any upsides. Again, see the banana example.
- Const-me 6y ago> See React What about React? They say right on their front page: “Build encapsulated components that manage their own state, then compose them to make complex UIs.” That’s a textbook definition of OOP. > it is better to deal with it without using OOP That’s a famous example but why do you think it’s always better? Sometimes, like when dealing with graphs, holding the jungle with the banana is exactly what you want. > If the focus of your code is reusability and modularity My primary focus is meeting requirements and budget. All technical decisions about reusability, modularity, performance, and the rest of them, are driven by these two. Some projects don’t need reusability at all, because that’s research, or a proof of concept, or a video game that won’t be maintained once launched. In other cases, being too aggressive about eliminating duplicate code can harm long-term maintenance. More likely to happen in higher-level parts. You introduce an abstraction, then you need to handle just one special case where the code being reused needs to behave differently and introduce a parameter. Repeat a few times and you now have tons of parameters, flags, and other crap no one understands, not even you. This happens regardless on OOP/FP/procedural, the crap is different in these cases but its effect on maintenance cost is equally bad. Wouldn’t happen if you would be more conservative about introducing abstractions, and instead copy-pasted a few lines of code here and there. > for most modern programming the performance cost is no longer a factor that matters Almost everything has a performance budget. For a web app difference between 1ns and 1ms doesn’t matter at all, but difference between 100ms and 1 seconds still matters, users will complain, search engines will downrank. Desktop apps ideally need to respond within 17ms because mainstream displays render at 60Hz. Performance cost of immutability is huge, can be 1-2 orders of magnitude, for 2 reasons. (1) memory allocations are relatively expensive (2) CPUs have cache hierarchy, main memory is like 20-40 times slower than L1D cache, each time you allocating a new immutable object it’s pretty much guaranteed to be out of caches. Still, there’re many cases when immutability is fine. C# immutable structs are awesome, unlike classes they’re free in terms of memory allocations, and they are usually on stack which guarantees they’re well cached. The upcoming C# 9.0 has a language support for immutable classes, pretty sure I’ll use it a lot once released and debugged. > Games and Databases are two examples where FP may not be the most appropriate paradigm due to the performance critical nature of the areas. Also CAD/CAM/CAE, realtime multimedia, some projects in embedded esp. real-time stuff. By the way, these areas are what I mostly do for a living. > If your class does not hold mutable state then essentially it's just a class repurposed as a namespace with syntactic sugar I like that sugar, and using that approach quite a lot in my code. For example, private methods and fields are invisible from outside, makes life easier because they don’t show in intellisense. I disagree that OOP promotes mutable state for cases when it’s not needed, it all depend on the language. JavaScript or Python don’t support immutable properties of their objects, but C# and (to lesser extent, but still) C++ do. However, the real value of OOP is when you have to deal with complex mutable state. Every single time mutable state is essential to the problem (rich GUI is just one area where it’s the case, there’re others), OOP has no good alternatives.