>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.