>Have very little idea, I don’t do web development.

Then I would say you are a bit behind the curve when it comes to what the majority of people are doing in UI development. The majority of UI development happens on the web. Current practices involve using a functional paradigm to deal with mutable state. The pattern is called Functional Reactive Programming. FRP for short.

>I think the majority of programmers nowadays, and have been for decades, working on internal line of business applications. No reason to generalize their experience over the rest of the software development.

I'm generalizing over a vast majority. The vast majority of SW development is web stuff and basically in web development performance is not the priority. Useability is. Basically people choose languages and frameworks like ruby, php and python over C++ for ease of use. Software development bootcamps emphasize javascript not C++.

These languages are so slow that it doesn't matter if you follow the functional style or not.

>JS is merely passing data to WebGL APIs. These APIs are implemented in web browsers, and underneath browsers in GPU drivers. Both modern browsers and GPU drivers have millions of lines of code written in C or C++, and JS is not performant enough to replace these, not even close.

Yeah I know. Don't write your OS or OS drivers in javascript. In general the platform is implemented by one guy and everyone else operates in his universe. Most web developers and even game developers won't get into the internals of OpenGL.

>Yes, and that’s usually a good thing. Here’s a method: https://docs.microsoft.com/en-us/uwp/api/windows.storage.str.... You can’t write bytes to a stream without the stream. From API design perspective that’s a feature, not a bug.

You missed the point. Object.write is worse than write(stream) because Object can hold more things than just a stream. If you implemented Object.write instead of write(stream) then your write method is forever tied to irrelevant context. Again see the banana gorilla jungle example.... literally the addOne method cannot be reused without creating a banana, a gorilla, and a jungle.

If you want to restrict your function to operate on certain data types you do this by restricting the input parameters. That's it. There is no need to attach it to irrelevant context when it doesn't even really touch other parts of the state.

>Visibility of that state. Usability of the API. Composability of the overall thing.

In FP you hide private state in functions. It is hidden anyway. "C" below.

A -> function(A){return B(A, C)} -> B (C is hidden state)

If you think about your programs this way where hidden state is ephemeral you never will have objects that are in a state of half correctness. The object only has two states: Existence or non-existence, never a state where only half of it's properties are initialized. The hidden state is forever stored within the function expression, ephemeral and inaccessible as it should be.

This is 100x better than the explicit use of "private." Hidden state in this case is truly hidden by structure rather than by syntactic tags.

Useability is equal. As you yourself as said object.verb() is semantically equivalent to verb(object).

Objects are not more composable than functions. The only way to compose objects are through inheritance, (which is bad) and object composition which requires the parent object to be aware of the child Object.

Example:

class B():
....

class A()
def __init__(self, B)
self.b = B

A is aware of B, therefore A is not modular. You have to customize A to be aware of B to compose it with B.

universal function composition:

def compose(f: A->B, g: B -> C): A -> C {
return function(x: A){return g(f(x)); }
}

def addOne(x: int){
return x + 1;
}

def timesTwo(x: int){
return x * 2;
}

addOneThenTimesTwo = compose(addOne, timesTwo)

addOne is not aware of timesTwo, timesTwo is not aware of addOne, compose is universal meaning it works on any function of type A -> B.

In terms of composition. Combining functions to form other functions hands down beats combining objects to form other objects. Literally no contest. It's one of the defining features of FP. All your FP primitives are literally tiny modular bricks that your compose into data pipelines that pump data from Input to Output. It is at the two ends of this pipeline where the functional style breaks down and you have to either start breaking rules or using complex abstractions to deal with IO and mutable state.

>The internal state of the object returned from setupConnection method can be just the TCP socket, or it can be a socket + AES decryption + a decompressor.

These are all static and stateless IO functions. You're not really doing OOP without an internal mutable var. You could literally rename that class to namespace. (I'm not too familiar with C# but I'm assuming the use of the word static means that the function is not tied to instantiated state meaning all state arrives in as a parameter negating the need for using the word "class" over "namespace")