ClojureScript vs Core.Async debate – the last updates.

So, my old post made to Reddit, and as I expected, lots of people complained about my conclusion. I still find damaging that Clojure community have this huge energy on defending “core” solutions, even when they are low-level, impractical, or (in this case) does not work well, if it works at all. But, well, I decided to clarify some of the posts, and answer some of the comments that people told me would, supposedly, “solve” the problem. I already answered these questions on other forums, so I’ll try to re-use some of my comments:

Interop with <p!

Some people asked about interop with <p!. Honestly, when I made the article, this option did not exist. Even then, a Promise can be rejected and resolved with arbitrary data, so to translate this code to ClojureScript means capturing the original result of <p!, check if it’s an ExceptionInfo, with the right type, and extract the right part. It’s also harder to compose IMHO (like, with Promises, you can chain actions, then if any of them fail, you can catch the error and the promise is back to the “success” phase). But at least, now it’s less complicated – although I would say, if you’re going to add a library to your project, why not add funcool/promesa instead of core.async? Remembering that promesa is both faster than core.async, and its constructions can work with any arbitrary data, not only promises, so you can treat all code as if it’s async (or sync), without needing to remember which ones are promises, and which ones are not…

Just .pause and .resume constantly

This works, indeed. For example, with sockets:

(.on socket &quot;data&quot; (fn [data]
                     (.pause rs)
                     (async/put! chan data #(.resume socket))))
(.on socket &quot;end&quot; #(async/close! chan))

But not all callback-based async code in ClojureScript allow you to pause events. Node.JS Socket do, WebSocket in browser don’t. Also, NPM package pg, when you query with a cursor, also will not allow it. In this case, there’s nothing you can do, really – you will either drop messages, or an exception will happen.

Use offer!

(go (>! and put! both are fragile with callbacks, because you can’t really “park” or “block” threads in Javascript. Keep put!ing messages in a channel, and you’ll hit an exception “No more than 1024 pending operations” (or something like that). So people asked me to use offer! or make a sliding buffer, etc. This doesn’t really solves the problem if you can’t drop messages – and I do have lots of cases when this happens. There were some people that told me that dropping messages is part of the life, and I wholeheartedly disagree – there are LOTs of situations when you can’t loose anything – bank transactions, socket messages (you can’t reconstruct the payload if you lost part of it), downloads, etc. There are ways to mitigate this, for example:
(more…)

Why I tend to avoid core.async?

It’s no surprise that I don’t like core.async very much. For starters, it make my functional composition looks like imperative programming again. There’s also multiple issues that you need to be aware of (like, don’t use async/put! because you will have problems, deadlocks that are difficult to predict, go blocks don’t compose over functions so you loose lots of helper macros like delay).

But the most important reason is that most of the time, I’m working in ClojureScript. And it’s impossible to migrate callback to core.async.

Well, you may be tempted to write something like:

(js/someFunction &quot;i&#039;m async&quot; &quot;lol&quot; #(async/put! some-channel %))

And one day or another you’ll have the dreadful Assert failed: No more than 1024 pending puts are allowed error. There are multiple ways around this problem, but none of then work if you can’t lose messages.
(more…)