The blog post fails to draw a proper distinction between Future
itself and the way it's commonly used, IMO. You could write pure-functional code with Future
, if you only ever wrote Future
s that called pure, total functions; such code would be referentially transparent and "functional" in every remotely reasonable sense of the word.
What is true is that Future
s give you limited control of side effects, if you use them with methods that have side effects. If you create a Future
wrapping webClient.get
, then creating that Future
will send a HTTP call. But that's not a fact about Future
, that's a fact about webClient.get
!
There is a grain of truth in this blog post. Separating expressing your computation from executing it, completely, via e.g. the Free monad, can result in more efficient and more testable code. E.g. you can create a "query language", where you express an operation like "fetch the profile photos of all the mutual friends of A and B" without actually running it. This makes it easier to test if your logic is correct (because it's very easy to make e.g. a test implementation that can "run" the same queries - or even just inspect the "query object" directly) and, as I think the blog post is trying to suggest, means you could e.g. combine multiple requests to fetch the same profile. (This isn't even purely a functional-programming concern - some OO books have the idea of a "command pattern" - though IME functional programming tools like for
/yield
syntax make it much easier to work in this way). Whereas if all you have is a fetchProfile
method that, when run, immediately fires off a HTTP request, then if your code logic requests the same profile twice, there's no way to avoid fetching the same profile twice.
But that isn't really about Future
per se, and IMO this blog post is more confusing than helpful.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…