I had done a little bit of OO before diving into functional, but what really got me about functional was "the same inputs always produces the same outputs" and "no side effects"
In OO (the kind I've seen, and I've not seen Smalltalk, mostly C++), it's common for a member function to just go ahead and modify the member variables it needs to modify. This is considered "good encapsulation," but it's horrid for reading code and likewise horrid for parallelizing anything.
When you take that practice to the logical conclusion, you can end up with a member function like "void update();" (let's pretend that our class is a physics engine and this function presumably takes velocity and time step and increments position). Some early advice I got for writing maintainable code was "assume that whoever is maintaining the code after you is smart and in a hurry," and that sort of code just breaks that advice. If I see that kind of function, I need to dive into it to figure out what's going on. Whereas if I saw "state.position = update_position(state.velocity, state.dt);" I can make an educated guess about what's going on and move on.
I'm making myself a little angry here, so I'll wind down. These are the main points anyway, this sort of functional style feels like it takes something in 4D space where I have to twist my brain into a klein bottle to figure it out and puts it into 2D space where I'm like "oh, that's all there is to it then."
To your working theory, I see what you're saying, but I think I lean towards preferring poorly done functional code as opposed to well done OO code, because the functional code will be easier to test and shape into good code, whereas the OO code might get fragile over time. But let's be honest, it's not like "well done OO code" is an option we expect to have on the table :D
In OO (the kind I've seen, and I've not seen Smalltalk, mostly C++), it's common for a member function to just go ahead and modify the member variables it needs to modify. This is considered "good encapsulation," but it's horrid for reading code and likewise horrid for parallelizing anything.
When you take that practice to the logical conclusion, you can end up with a member function like "void update();" (let's pretend that our class is a physics engine and this function presumably takes velocity and time step and increments position). Some early advice I got for writing maintainable code was "assume that whoever is maintaining the code after you is smart and in a hurry," and that sort of code just breaks that advice. If I see that kind of function, I need to dive into it to figure out what's going on. Whereas if I saw "state.position = update_position(state.velocity, state.dt);" I can make an educated guess about what's going on and move on.
I'm making myself a little angry here, so I'll wind down. These are the main points anyway, this sort of functional style feels like it takes something in 4D space where I have to twist my brain into a klein bottle to figure it out and puts it into 2D space where I'm like "oh, that's all there is to it then."
To your working theory, I see what you're saying, but I think I lean towards preferring poorly done functional code as opposed to well done OO code, because the functional code will be easier to test and shape into good code, whereas the OO code might get fragile over time. But let's be honest, it's not like "well done OO code" is an option we expect to have on the table :D