Maybe what I'm trying to say is that a lot of functional programming takes place within the OO model when it's efficient to do so; but functional paradigms just generally ignore state altogether, so absolute purity doesn't leave a route for daily coders writing regular programs to do their jobs.
This also translates well to OOP in the form of things like hexagonal architecture (eg: business logic is pure, and state is modified by a database adapter), or to modern frontend programming (eg: the render tree is pure, visual representation state is stored/modified with by React), including flux architecture (eg: reducers are pure, state is stored/modified by Redux).
I really like this presentation about it: https://www.destroyallsoftware.com/screencasts/catalog/funct...
Maybe this all comes down to what I find easier to follow in 200 code files and we're talking about roughly the same thing. If the general rule is to make logic as independent and no-need-to-retype-it as possible in the hierarchy, I'm onboard. And letting functions manage state themselves makes no sense; even in OO paradigms, functions should be pure and not rely on the state per se. (Put in plain terms, I make heavy use of getters and setters on instances; but complex functions are almost always static, and take instances of the class they're in to modify, rather than reproducing those functions and having them work on their own instance).
Well, but who really follows that idea? What usually happens is, that the state is stored in the object (of a class) and the result of subsequent method calls depends on previous calls and arguments, since it changed the state of the object. Maybe there are even calls to other objects in the system changing their state, and in turn changing return values of their methods.
Also: If we have actual functions (in a mathematical sense), then they depend only on their inputs / arguments. Why then have them in a class, and not in say for example, a module?
This speaks to the muscle memory of daily coders way more than to the details of FP/OO.
You could easily make the same argument about “absolute encapsulation”.
In data types!
> But so many functions are more comprehensible when they take place bound to the scope of what it is they're acting upon
To me, the most understandable function (lowest context needed, lowest cognitive overhead) is a black box that takes type x as input and produces type y as output, without side-effects
> I don't think that thinking in terms of objects or even global states should be considered a code smell
Classes can mix state and behaviour. I prefer when state is encoded in types and behaviour in functions, instead of having implicit state changes in a class, because it is more difficult to track, and constraint.
Of course, in the real world, if a library or platforms uses OOP, so be it. I am not dogmatic. But ideally, I avoid OOP because of this implicit mixing of state and behaviour.
Yes. With guardrails. I mean, I do a lot of writing in JS/TS but I'd never write something that tacked a dynamic property onto some class and picked it up later. That's just gauche.
> a black box that takes type x as input and produces type y as output
I agree, but I'd rather keep that function in Class X. If it's specific and X is a final/protected class, I'd say `protected doSomething()=>Y` where the argument is the implicit `this`.
I'd never allow some other thing to run this function, definitely not some other object floating out there; if it were going to be run that way it would have to be a `static DoSomething(x:X)=>Y` ...but I would still keep it in the file for X.
True, however we must be careful not to go completely bananas either; it's really hard for a reader to piece back together a full mental picture if the functionality is spread into dozens even hundreds of general-purpose 3-line functions.
Simple, `y = f(x)` types of functions are indeed the easiest to understand, but you might be no closer to understanding what the code is actually doing.
Of course the functions can be grouped in modules. It is the same problem as having god objects, having lots of methods or many classes in OOP (it is orthogonal to OOP or functional programming).
Because, everything you are saying is either forbidden nor discouraged in (pure) functional programming. In fact, it is totally orthogonal.
The point of functional programming is solely to prevent the same code to behave differently just because it is used/called in different parts of the program. You can still use objects, you can still make them have methods that operate on only a limited part of the state and so on. No problem with that, I do it all them time in fully pure functional programs. In fact, I think this is best practice.