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.
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.
> trying to mix the two fundamentally non-composable things together. You still have to do the conversion yourself.
I think the fact that you can do the conversion shows that they are composable. As I've written in the blog post, I don't mind verbosity verbosity much, as long as it gets me some control.
> The point of the colored function is that the color is a leaky abstraction.
And I think that's where the difference lies. In JS, an async function will leak all up your callstack, while in contrast in Rust, you can clearly control where the leaking stops.
> 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.
I think that's fair, but I haven't really had much problems with that in practice.
Go. Go eliminated the distinction. Everyone of his points about JS/C#/Dart all tick the same boxes he calls out as problematic in Rust as well. The size of the problem may be simpler but you haven't eliminated it.
Everything is composable if you wrap it appropriately. Saying that since you can convert something into a newer more composable form doesn't imply that the original is composable. It just means that since we can write code everything is composable with the right amount of work. What people actually mean when they say two things are composable is that you don't need a shim to compose them together.
> 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.