Promises represent a calculation in progress, rather than one to occur later, which muddies the discussion a bit, but I would suggest that’s still declarative. If the code was rewritten using something like
data.task, or a
Future, it would be pretty clearly declarative.
Focusing on streams though: Note that the call to
getJSON doesn’t trigger a side-effect, it just returns a stream; observing the stream it was triggers the side effect. If I call
getJSON outside of the context of the
flatMap, I get back a stream. The HTTP request itself has not yet been triggered, and won’t be triggered, until the stream itself gets observed. We’ve merely declared that at this point, we want the results of an HTTP request merged into the main stream.
In a pure functional language, the runtime would enforce that, should you call
getJSON with the same parameters, you’d get back the same instance, which would make a call to
Which means that the Epic function provided to
redux-observable is pure, referentially transparent, and does not produce side effects, because streams don’t produce side effects until they’re observed, and the stream returned from the Epic is observed at the edges of the system. It’s not merely that we wrap things in functions; it’s that we wrap them in objects that represent the results of those side effects without being the side effect.