7 ms·
Quoting this article's opinion on the 'What colour is your function' article > One the one hand it's a great article that hits the nail on the head why using a
by hannofcart 6y ago
Quoting this article's opinion on the 'What colour is your function' article
> One the one hand it's a great article that hits the nail on the head why using async/await in JS (and other languages) is very painful
> Rust's async/await even though - you might have guessed it - it doesn't apply!
So the author starts off by declaring that the colored functions problem only applies to other languages but not to rust.
Soon after, he takes exception with the claim "You can only call a red function from within another red function".
His primary argument in support of this is that in rust you can execute an async function blockingly in an executor. And to do vice versa, i.e. call a sync function in an async loop, that you can either block the event loop or hand it off to a different machinery.
The fact is, both of these things can be done in other async runtimes as well. For eg. it's a near identical scenario in python async. Like others have pointed out in this comment thread, this is true in Scala too. Perhaps the author is unaware of this?
So yes, rust does indeed have the colored function dichotomy, as any async runtime would, the author's angry assertions to the contrary notwithstanding. (I say this as a fan of both rust as well as async runtimes, which I feel are a nice fit for certain use cases.)
- EugeneOZ 6y agoIndeed. Also, "very painful" is subjective. I never had issues with async code in JS (well, I had bugs, but it's not a fault of the language). There's nothing painful in async JS.
- 1f60c 6y agoHaving to use an async immediately invoked function expression in Node scripts is kind of a pain, but I agree.
- MaxBarraclough 6y agoAgree, JavaScript's approach to concurrency and asynchronous events is one of its strong points. The model of There is exactly one thread, and everything that could be asynchronous is asynchronous works nicely for web work, keeping things relatively simple (of course, race conditions are still possible) while avoiding the pitfalls of full-bore multithreading. I imagine it also makes things far simpler for the browser engineers. It's the opposite of the old Java Swing approach, where applications would often have far more threads than they really needed. (iirc, NetBeans idles with something like 30 threads.) The await/async feature seems like a sensible addition to JavaScript, but I'm open to the idea that there are alternative solutions that would be even better. As an example, I don't know much about what Java is up to but I understand it's not going with await/async exactly.
- skohan 6y ago> There is exactly one thread, and everything that could be asynchronous is asynchronous works nicely for web work, keeping things relatively simple It might keep things simple, but I don't know if this is really a sensible design constraint going into the future. Parallelism is where performance is going to come from in the future, and having the web - the most common way most people consume software - be single-threaded seems like a massive waste of hardware. If I have a 16 core processor just so the add trackers in each of my chrome tabs can run in parallel, this is a world I don't want to live in.
- girvo 6y agoGenuine question, what would the ad trackers be able to do with runtime level parallelism in the JS runtime that they can’t achieve now? Do they do a lot more blocking calculation than I’d expect?
- vbsteven 6y agoStuff like parsing JSON is typically still blocking. I’m sure there are other forms of blocking computation. JS being single threaded means that while some tracker is parsing a big json blob your website becomes unable to handle input events until the tracker is done. Let’s say there is an option to do this in some form of threaded worker or coroutines then the main UI thread does not become blocked.
- lovasoa 6y agoThe original article was mainly centered around javascript, where you cannot spawn an executor to synchronously get the result of an async function.
- janjones 6y agoAgreed. Colored functions can be solved, though. See Unison[1] or Zig[2]. [1] https://jaredforsyth.com/posts/whats-cool-about-unison/ https://jaredforsyth.com/posts/whats-cool-about-unison/ [2] https://kristoff.it/blog/zig-colorblind-async-await/ https://kristoff.it/blog/zig-colorblind-async-await/
- littlestymaar 6y agoZig has a really paradoxical reaction to “function coloring”: on the one hand, they create a specific system to avoid async/sync split, but on the other hand, because allocating functions need an allocator passed as argument, they are recreating the exact same problem in another place. (Allocating functions are red, zero-alloc are blue and you can't call a red function from a blue one). Same problem with Go's `Context` or error as a return value. Same problem with pure/impure functions, or functions returning optional, or platform-specific functions, etc. Sync/async is not special, it is just one instance of a problem that comes up pretty much everywhere (Algebraic effects may be a solution, but I'm not sure).
- dnautics 6y ago> Allocating functions are red, zero-alloc are blue and you can't call a red function from a blue one This is not entirely correct analogy. You can embed your allocator inside one of the parameters, too, as a strategy (perhaps a certain type of "object" should carry it's allocator with it). Then uncolored generic functions could operate on allocator-bound and allocator-unbound "objects" alike, even if say the generic function calls a "object method" that performs an allocation in one case but not the other.... You just have to be careful about how to handle errors. There is no equivalent for async. If you were going to be serious about function coloring in zig, the place where there is function coloring is functions with error return values but that's actually a reasonable place to have function coloring, and still, it's easy to build seams in both directions, so a red function can call a blue function, and a blue function can call a red function pretty easily.
- littlestymaar 6y ago
- hobofan 6y ago> So the author starts off by declaring that the colored functions problem only applies to other languages but not to rust. > For eg. it's a near identical scenario in python async. I'm at no point claiming that Python is colored (the "What Color is Your Function?" post does). It seems that by my interpretation Python may indeed be as uncolored as Rust (I've only used it in a very limited fashion). Can't compare Scala as I haven't used it. From the original post: > This is where the “red functions can only be called by red functions” rule comes from. You have to closurify the entire callstack all the way back to main() or the event handler. I think that very much supports my point, and I don't see why async runtimes should not be allowed as a tool to call a async from a sync function. In some languages (like JS) that have their own runtimes, you don't really have that choice though.
- zaphar 6y agoYou are getting pushback because people don't agree with your core assertion. The point of the colored function is that the color is a leaky abstraction. No matter the language you are using an async function call inside a sync function must be converted into a sync call and vice versa. Some languages make it easier than others to do but you can't escape the fact that you must do that conversion. Rust assists you by enforcing the distinction with compile time type checking. But all that is doing is yelling at you that you are trying to mix the two fundamentally non-composable things together. You still have to do the conversion yourself. You still have to do extra work to accomplish the conversion. Also it's just ugly to have layer after layer of async/sync wrapping going on. So what ends up happening is that you end up preferring one color over the other. Either you try to keep everything asynchronous or synchronous to avoid the whole thing.
- shakow 6y ago> The point of the colored function is that the color is a leaky abstraction I disagree with this take; I understand the point of the original “What color is your function?” as colored functions creating an impassable divide between Promise-wrapped values and sync code. Indeed, in the end, the author mentions e.g. C# as not being colored, because even if sync/async functions are different, it features escape gates to unwrap promises and bring them back into the sync world.
- jedimastert 6y agoI'm not usually a JS person, but you can do the same thing with Promises too, right? Did JS Solve(tm) "colored" functions?
- shakow 6y ago> but you can do the same thing with Promises too, right? No, Promises can only be interacted with within the async framework. There is no ways to 1. Call an async function/get a Promise in a sync function and 2. “Extract” the value in the promise and use it as naked value. JS would need e.g. a “stop there, wait for the promise to result, unwrap its content and give it to me” instruction to be like Rust in this case.
- jedimastert 6y agoYou know what, you're right. I thought there was an "unwrap", that's my b
- shakow 6y agoNo problem, knowledge comes from suffering ;)
- resonantjacket5 6y agoYou can technically wrap the promise and spin lock on it till it resolves. Aka forcibly wait on an async function in a sync function. There are some npm libraries that provide it. I've used a couple times (for some hacky scripts), though obviously don't use it in the browser.
- pitaj 6y agoAFAIK, you can't do this from JS, you have to have some engine integration, as the busy loop in JS will prevent the event loop from working. For instance, this will essentially halt your runtime: let y; Promise.resolve(123).then(x => { y = x; }); while (!y) {} console.log(y)