Live data from Hacker News

Callbacks are imperative, promises are functional

blog.jcoglan.com

101–110 of 154 posts

Re: Callbacks are imperative, promises are functional

#101

Earlier quoted context omitted.

Generally this is of course good advice, but in Haskell it is common practice to use very short names (e.g. x, x', xs, ...) if the context is clear (which it usually is due to small scope, clear function names, type signature, etc.). This makes code much more concise and readable (it also makes it look very "mathematical").

> (it also makes it look very "mathematical") Has that ever been an advantage?

For people that like math, sure, why not. When implementing mathematical concepts, if you squint at Haskell code you can see the original formulas, which should make it easier for people used to this way of thinking.

EDIT:

I'm not implying it's useful just for programming "math stuff", after all, everything can be reduced to a mathematical problem - including game engines[1], web application frameworks[2], etc.

[1] http://www.cse.unsw.edu.au/~pls/thesis/munc-thesis.pdf [2] https://github.com/yesodweb/yesod

Re: Callbacks are imperative, promises are functional

#102
post #57

This code doesn't look right to me: // list :: [Promise a] -> Promise [a] var list = function(promises) { var listPromise = new Promise(); for (var k in listPromise) promises[k] = listPromise[k]; Perhaps the assignment is supposed to be the other way around? for (var k in promises) listPromise[k] = promises[k];

I asked the same question in Twitter. Turns out James was actually augmenting (i.e. modifying) the array object `promises` to behave as a promise itself. I don't think this was a particularly beautiful way of doing it but it seems to work now that I think of it.

Promise libraries, like RSVP.js [1] he referred to, typically implement a way to construct a promise with a depends-on-many relationship, as a function possibly called `all([p1, p2, ...])` (with the same type signature as for `list`), `and(p1, p2, ...)` or something similar.

IMO, defining the `list` function that way would've been clearer to the reader and more FP'ish, treating the `promises` argument in as a value and not a mutable object.

[1]: https://github.com/tildeio/rsvp.js/blob/master/lib/rsvp/all....

Re: Callbacks are imperative, promises are functional

#103

Not to focus too myopically on the given example, but I can’t help but wonder why it’s a requirement that the first file be handled specially? A less contrived example would make the argument more convincing. If I wanted to compute the size of one file relative to a set, I’d probably do something like this: queue() .defer(fs.stat, "file1.txt") .defer(fs.stat, "file2.txt") .defer(fs.stat, "file3.txt") .awaitAll(functi…

>> but reading files in parallel would presumably be slower since you'd be jumping around on disk There is a lot of engineering that goes into making parallel reads go fast. Some combination of the file system and disk controller will probably be smart enough to recognize the opportunity for sequential reads and execute them as such if possible. This is not always true, and it does not undermine the rest of what you…

Stat just reads metadata that is (hopefully) cached in memory. Linux does not have any async APIs for reading metadata anyway. Examples are always a bit contrived, it doesn't matter.

Re: Callbacks are imperative, promises are functional

#104

Earlier quoted context omitted.

Various incarnations of the Promise monad have existed for quite a while, even in JS. The oldest one I can think of is MochiKit's Deferred, inspired by Twisted's. That one worked (and still does) seamlessly with any callback code.

(Twisted was inspired by the work I just pointed to in my answer. Not to take away from yours -- I wasn't familiar with MochiKit.)

Of course, using monads for asynchronous tasks is an old trick and E has always been ahead of its time (like many other languages ...)

Re: Callbacks are imperative, promises are functional

#105

Not to focus too myopically on the given example, but I can’t help but wonder why it’s a requirement that the first file be handled specially? A less contrived example would make the argument more convincing. If I wanted to compute the size of one file relative to a set, I’d probably do something like this: queue() .defer(fs.stat, "file1.txt") .defer(fs.stat, "file2.txt") .defer(fs.stat, "file3.txt") .awaitAll(functi…

> I just feel like they might be a bit heavy-weight and a lot of API surface area to solve this particular problem. The surface area is `.then()`

Lack of standardization makes people go crazy. If another programming language had an API this simple, people would never think it is heavyweight. But because you're always rolling your own, people get obsessed with the smallest things in js-land.

Re: Callbacks are imperative, promises are functional

#106

Earlier quoted context omitted.

The point is promises free you from wanting or needing to know about the order that things happen in. I hear you saying you fear promises, because it means it would get in the way of your ability to know that. But the truth is once you embrace them, that need becomes unimportant. The idea that webservers are "all about side effects" gives me a chill. The whole architecture concept of HTTP is no side effects , so to c…

As someone who's started moving from the imperative world, albeit in Java, C# and Ruby based work rather than JavaScript, I can say that letting go is the hardest part. However, when you learn to stop worrying and let the runtime decide it's so much nicer. It turns out that people have already optimised the framework, so at worst it's just as fast as the code I wrote. At best it's faster because the framework knows m…

Just think of it as forking and joining threads...

Re: Callbacks are imperative, promises are functional

#107

It is hard for me to fathom the negative feelings towards Promises. They are quite clearly a great way to perform async programming in a civilized way (see Twitter's Future/Promise in Finagle on github). JDK 8 will even have the equivalent in CompletableFuture. The only thing better is to combine Promises with coroutines for a more linear programming style like in Flow: http://www.foundationdb.com/white-papers/flow/

Thanks for this--I mentioned finagle to jcoglan on twitter yesterday after I read his blog post, and I don't think he was aware of the similarities.

I actually didn't know about futures until I learned about scala and finagle. I watched a talk on twitter's service stack given by marius eriksen and was blown away. My coworkers heard me rambling on about futures for weeks afterwards, and I found that it was difficult to explain what was so great about them. So I'm not surprised at the negative reactions in the comments here (although jcoglan did a much better job of exlaining them than I ever did).

Re: Callbacks are imperative, promises are functional

#108
post #74

I don't agree that there is any fundamental difference in functionality between callbacks and promises. Promises don't somehow magically make asynchronous code easy to write while leaving callbacks out in the cold. They have very similar strengths and weaknesses and I didn't find any of the OP's arguments compelling. In fact, if I had to choose, I would take the opposite view and say callbacks are neater, cleaner and…

Promises are values, and you can use them to compute things. Callbacks are procedures, and are non-composable in non-trivial ways (you can chain callbacks very simply, but that's basically it).

Re: Callbacks are imperative, promises are functional

#109

This is an interesting perspective. But to me, even having spent a year on a large node.js project, I just don't see how promises would have simplified things at all. If you have some crazy graph of dependencies, I can see how breaking out promises could help simplify things. But I don't feel like that's a super-common scenario. The author says: > * [Promises] are easier to think about precisely because we’ve delegat…

I can speak your comment, since my side project is a Node.js server that talks to several APIs, a database, and N web clients. Like you, I've worked more than a year on it, but I had a positive experience with Q [1] and jQuery promises. Promises make async code easy to manage, even at scale. Each API request gets its own promise. What happens inside that promise doesn't matter, as long as it returns a result or an er…

In other words, promises allow us to separate concerns. Document retrieval is one concern, collation another.

Other programming languages have this too. They're called a 'METHOD'. Sorry, couldn't resist.

On a serious note, look at your code in here:

https://github.com/fruchtose/muxamp/blob/master/lib/playlist...

And look at your 'playlistCount' function on line 39 (which for no apparent reason you've made a variable).

Now I can't understand how a promise there is helping your programming. In fact it seems to have vastly increased the complexity of the code and it is now completely unclear from a quick scan how the method works, what the program flow actually is.

It should be a much shorter function, literally just this:

    function playlistCount(){
        return db.query('SELECT COUNT(id) AS count FROM Playlists;', function(rows) {                   
            return parseInt(rows[0]['count']);
        });
    }
Your version is 28 lines!

28 LINES. HOW? For a simple COUNT!

Actually to be fair to promises, 50% of the problem here is that you've not abstracted your db code and unnecessarily repeat boiler plate connection code again and again and again.

But a big part of the problem is that you can't just throw an exception and let it bubble up the stack, you're constantly having to baby sit the code, and that is the promises fault.

(unrelated, but as a mini-code review though I've never used node.js but the oft repeated line of `dbConnectionPool.release(connection);` in the connection failure code is an immediate code smell to me, it looks like rain dance code, why would you have to release a failed connection? It failed, how can it be released?)

Re: Callbacks are imperative, promises are functional

#110
post #76

Not to focus too myopically on the given example, but I can’t help but wonder why it’s a requirement that the first file be handled specially? A less contrived example would make the argument more convincing. If I wanted to compute the size of one file relative to a set, I’d probably do something like this: queue() .defer(fs.stat, "file1.txt") .defer(fs.stat, "file2.txt") .defer(fs.stat, "file3.txt") .awaitAll(functi…

do f1 Or, if you prefer a list do fs And that seems to be one small example of why you may have already invented monads. I've been loving the impact of Javascript—modify and immediately see it on the browser—but every time I'm not using Haskell I miss it dearly.

Have to admit that has also been my reaction to some of these javascript async frameworks based on promises or deferreds. Congratulations, you've reimplemented a quirky ad-hoc variant on the continuation and error monads.

Perhaps people don't spot the link as easily because monads are usually explained in terms of a type system, and javascript is untyped? (Or perhaps just because Monad is a very abstract abstraction :)

Post reply on HN