I write code, front-end and back-end, and like deploying it on AWS. Software Developer for 20 years, and still love it. Amateur Powerlifter & Parkourist.
You wrap the side effects because they throw. If you didn't, they'd throw. You instead return a Result, which is composable. You can also return a Promise, which is also composeable. These aren't procedural, they're functions you can combine together like one -> two -> three or Promise.resolve(value).then(something).then(another). If you don't return a Result or a Promise, then yes, it's procedural.
Please assume benevolent intent. My comparison to Feynman was realizing I should of defined why Functional Programming eskews throwing Exceptions, and instead returns results from functions. If you don't know that context beforehand, then the ideas seem strange in async/await syntax.
If you call a server, you can return a value and have it not throw. You simple wrap the catch, and say "it didn't work". Why it didn't work is important, but beyond status code and response.ok, the fetch interface doesn't give you much. You'll have to do all that work yourself around status code, protected data decoding vs. the common response.json(). If you do that, then you have a better error message that comes out, but the function is still pure: "it works or it doesn't". The side effect, fetch, you can use Dependency Injection or the Effect pattern (or mocks to test). In Elm, there are no side effects so this isn't a problem. In ReScript, it's quite interesting; they follow JavaScript side effects model, but still strive for pure functions with "mostly" mutability. Still, even in ReScript, you'd return something like Elm: some kind of type to pattern match on like "It worked" "bad status code" "bad data" or "network error". However, you have to like the functional style and pattern matching to do that. If you don't want to do all that work in non-FP languages like JavaScript/Python, that's fine.
I'm not saying FP is better. I'm saying this style is easier for me and others. If you like it, cool, here's how you do it. If you don't, cool.
Your examples aren't the same. It's same reason Go developers are ok with if err != nil everywhere, which I get; they like the simple and explicit. You manually have to create the variables value, then manually call the function checkResult, then put the value in it, then at some point wrap some of that with a try/catch. Promises or Result.bind do all that for you without a need of try/catch.
I am Software Developer, currently interested in static type languages (TypeScript, Elm, ReScript) mostly in the frontend land, but working actively in Python also. I am available for mentoring.
Promise is composable but also does eagerly side effects and if we define function as something which is referencialy transparent then Promise is not. It return depends from the "state of the world" or just depends from time. And it makes it procedure more than a function, procedure which returns some value to the caller.
Things which return value are composable but without monads doing composition with values wrapped by Either would look like your Go example where every function would check if we have left or right.
And such Either Monad allows for composition positive path totally not thinking that there is any Either and possible error.
When we look on this though we see that it is exactly simulation of procedural exception which allows code to work in positive path and just goto catch for errors. Even exactly that was one of reasons Monads in Haskell were such a thing. They allowed for pure functional composition which could do the same staff like procedural code.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
You wrap the side effects because they throw. If you didn't, they'd throw. You instead return a Result, which is composable. You can also return a Promise, which is also composeable. These aren't procedural, they're functions you can combine together like
one -> two -> three
orPromise.resolve(value).then(something).then(another)
. If you don't return a Result or a Promise, then yes, it's procedural.Please assume benevolent intent. My comparison to Feynman was realizing I should of defined why Functional Programming eskews throwing Exceptions, and instead returns results from functions. If you don't know that context beforehand, then the ideas seem strange in async/await syntax.
If you call a server, you can return a value and have it not throw. You simple wrap the catch, and say "it didn't work". Why it didn't work is important, but beyond status code and
response.ok
, the fetch interface doesn't give you much. You'll have to do all that work yourself around status code, protected data decoding vs. the commonresponse.json()
. If you do that, then you have a better error message that comes out, but the function is still pure: "it works or it doesn't". The side effect, fetch, you can use Dependency Injection or the Effect pattern (or mocks to test). In Elm, there are no side effects so this isn't a problem. In ReScript, it's quite interesting; they follow JavaScript side effects model, but still strive for pure functions with "mostly" mutability. Still, even in ReScript, you'd return something like Elm: some kind of type to pattern match on like "It worked" "bad status code" "bad data" or "network error". However, you have to like the functional style and pattern matching to do that. If you don't want to do all that work in non-FP languages like JavaScript/Python, that's fine.I'm not saying FP is better. I'm saying this style is easier for me and others. If you like it, cool, here's how you do it. If you don't, cool.
Your examples aren't the same. It's same reason Go developers are ok with
if err != nil
everywhere, which I get; they like the simple and explicit. You manually have to create the variablesvalue
, then manually call the functioncheckResult
, then put thevalue
in it, then at some point wrap some of that with a try/catch. Promises or Result.bind do all that for you without a need of try/catch.Promise is composable but also does eagerly side effects and if we define function as something which is referencialy transparent then Promise is not. It return depends from the "state of the world" or just depends from time. And it makes it procedure more than a function, procedure which returns some value to the caller.
Things which return value are composable but without monads doing composition with values wrapped by Either would look like your Go example where every function would check if we have left or right.
And such Either Monad allows for composition positive path totally not thinking that there is any Either and possible error.
When we look on this though we see that it is exactly simulation of procedural exception which allows code to work in positive path and just goto catch for errors. Even exactly that was one of reasons Monads in Haskell were such a thing. They allowed for pure functional composition which could do the same staff like procedural code.