Earlier quoted context omitted.
Not conceptually. From the perspective of the rest of the program, isPrime(x) has no side effect regardless of which method you use to implement it. If you are working in a purely functional language, then it makes sense to have introducing IO be a major change, as it has huge potential to make a function impure, and assuming IO is a pure function is roughly the equivalent of unsafePerformIO. However, in this case, w…
Of course it's different. What if the IO fails?
Escape from Callback Hell
71–80 of 86 posts
Re: Escape from Callback Hell
#72Earlier quoted context omitted.
That isnt the point, its that you have some nice code that does |var x = someBigFunction()| and at some point in the programs life, something inside someBigFunction turns async, you have a whole restructuring to do.
Then that's a breaking change of the someBigFunction()s interface and it should be treated with care, not just quickly patching on a promise and hope for the best. Javascript is single threaded so when you wrote someBigFunction() you didn't have to think of parallel side effects. If you suddenly pause the execution of someBigFunc() and allow the user to mess around with the interface, the global state that someBigFun…
var a = await someBigFunc()
or do
a
Javascript in its current state is not built for supporting CPS programming very well. You often end up needing to reimplement control flow primitives like while loops, break statements and exception handling since those don't play nice with async stuff.Re: Escape from Callback Hell
#73Earlier quoted context omitted.
Do you know if there are any good alternatives that are pure-ish JS? I know that same guy worked on tamejs but they don't seem to be working on that anymore...
There's tame.js from the same guys ( https://github.com/maxtaco/tamejs )
Re: Escape from Callback Hell
#74Earlier quoted context omitted.
Then that's a breaking change of the someBigFunction()s interface and it should be treated with care, not just quickly patching on a promise and hope for the best. Javascript is single threaded so when you wrote someBigFunction() you didn't have to think of parallel side effects. If you suddenly pause the execution of someBigFunc() and allow the user to mess around with the interface, the global state that someBigFun…
Fair enough. It might be a breaking change but wouldn't it be nice if instead of having to rewrite everything into continuation passing style (a boring and error prone process!) you could just do something simple like var a = await someBigFunc() or do a Javascript in its current state is not built for supporting CPS programming very well. You often end up needing to reimplement control flow primitives like while loop…
a Re: Escape from Callback Hell
#75Earlier quoted context omitted.
> They're just continuations, seriously, what's everyone's problem? That they're badly made continuations, without support from the language. > If you feel like your code is nesting too deep, you define the function elsewhere and just reference it by name. Then you don't get access to the current scope. At the cost of moving stuff out of where it's invoked, so making code harder to read. The problem with callback hel…
My favourite example of this is loops. Its very annoying to put an async call inside the loop since you need to rewrite the loop as a recursive function.
Once I started using the async library, all of these problems everyone is illustrating basically disappeared.
Re: Escape from Callback Hell
#76A great library for structuring your callbacks is "async": https://github.com/caolan/async I've only used it with node.js, but it's supposed to work in web browsers as well. It allows you to think a little more procedurally ("waterfall" is especially handy here) while writing CPS code. Very good.
Re: Escape from Callback Hell
#77I honestly find "callback hell" a lot easier to follow and understand than the vast majority of fixes everyone is coming up with. They're just continuations, seriously, what's everyone's problem? You define a function, it gets access to the current scope, it defines the rest of the program flow. If you feel like your code is nesting too deep, you define the function elsewhere and just reference it by name. Then you d…
A real continuation captures the entire execution context including the current call stack.
Instead what you get in javascript is a stack that's completely meaningless. There's no way to automatically route your exceptions to the real calling context, and there's no automatic way for you to be sure you're seeing all of your callee's exceptions.
If you really want to be sure you'll hear about the ultimate success or failure of an asynchronous call, every single asynchronous step needs to manually install it's own exception handler, trap any exceptions, and pass them back via a failure callback. You're basically doing by hand what the runtime environment is actually supposed to do for you (that being the whole point of exceptions).
Re: Escape from Callback Hell
#78Earlier quoted context omitted.
That isnt the point, its that you have some nice code that does |var x = someBigFunction()| and at some point in the programs life, something inside someBigFunction turns async, you have a whole restructuring to do.
This is just not something that happens in real life. You know what functions are going to be async up-front, and likely make them async even if you don't know, just in case. Since all IO in js is async by default, having a code that does a simple calculation and introducing IO into it is actually a very big change that warrants the refactoring you'll be required to do.
Consider the simple case where one wants to look up a value synchronously if one has it in memory, and go get it from storage asynchronously if one doesn't. That's a natural thing to want, but it's problematic in Node. The problem is not syntactic—you can easily write a function that calls back immediately in the one case and asynchronously in the other. It's that sync and async semantics don't compose well, so when you start to do anything a little complicated (e.g. launch N requests and call back when all N have either returned or failed), the two trip over one another. Working in a Lisp that compiles to JS, I had to write some surprisingly complex macros in order to get correct behaviour. I wouldn't dream of writing that JS code by hand.
Re: Escape from Callback Hell
#79Earlier quoted context omitted.
Functional programs don't make this easier. And don't say "monad transformer stacks" somehow solve this problem in an easier way.
Haskell definitely makes it easier. You can use preemptive green threads with almost all the ease of cooperatively multitasked code because of the prevalence of immutability. You get the performance benefits of non-blocking code. The simplicity benefits of blocking code. And (almost) none of the threading hell you get in imperative languages.
Re: Escape from Callback Hell
#80Earlier quoted context omitted.
That isnt the point, its that you have some nice code that does |var x = someBigFunction()| and at some point in the programs life, something inside someBigFunction turns async, you have a whole restructuring to do.
This is just not something that happens in real life. You know what functions are going to be async up-front, and likely make them async even if you don't know, just in case. Since all IO in js is async by default, having a code that does a simple calculation and introducing IO into it is actually a very big change that warrants the refactoring you'll be required to do.