I would argue rust is colored (and I'm not sure if there are any languages which are truly uncolored) but I would argue the original article this links to is quite specific to JS and more specific pre-async/await(promise) JS!!

So you can't at all carry over many of the arguments made there just like that.

Mainly in a more programming language agnostic way I would say:

1. We need at least three categories, instead of two: GRAY/UNCOLORED - function is fully call context independent; BLUE - function is expected to be called in a blocking/os-threaded context; RED - function is expected the be called in some form of async calling context.

1.1. The async context might be layered on top of a normal os context.

1.2. Function can potentially be compiler and or runtime generic over the calling context

1.3. There can be more calling contexts then RED and BLUE, e.g. interrupts and signal handlers.

2. You need to call the function in the right context, but if the way you call it changes at all is fully language specific. Furthermore type systems can prevent you from using it the "wrong way". Just because you have green thread support or similar doesn't mean you don't have colored functions. Especially when doing FFI function coloring often still is important to consider. Through languages might hide away one color as good as they can (which is always a best effort compromise, at least as long as you don't run a OS specifically made for the given prog. lang and even then hardware might still get in your way...)

3. You need to call functions in the right context, but that doesn't mean you can't change or layer the context inside of an function. E.g. the border between gray/uncolored and blue functions is vague so often everything is run in a blue context and a red context is in some places layered on top of a blue context. Through a language could decide to not do so! Still while you can run them in each other by ad-hook creating the right calling context, it is often not recommended due to performance aspects or increased likelihood of things like dead locks.

3.1. In rust we layer a red context on-top of a blue one, furthermore you can always create a red context inside of a blue function ad-hook. It's not perfect but super easy.

3.2. Lastly to some degree the whole red context in rust is just syntax/library sugar around using a blue context with certain conventions.

3.3. Any constraint about higher-order functions is not coloring but language specific. E.g. Rust currently supports functions as values (incl. closures). But it only has very limited support for higher kindred functions (or types) which are needed for having more than just basic higher-order functions. Which can currently impose some restrictions wrt. higher-ordered functions in an async context. The pending support for generic associated types should solve this problem.

4. Red functions need to be called in a red context, if this is more painful depends 100% on the language in question. Many languages default to a blue context, furthermore red context often allow MUCH more control over the flow of execution then blue contexts so it's not uncommon to have a bit different syntax around them. But if they are more painful to call is inherently a aspect of the programming language and not coloring on itself.

4.1. In rust you need to use the `.await` operator to call them. While you could argue that it's more painful, you can also argue it's less painful as it makes many thinks much less painful then a implicit await would.

4.1.1. A a side not I would argue in rust a `Future` is a red function and a `async` function or closure is red in source code but then get's compiled to a gray/uncolored function returning a red function. Which is more complex, but is also inherently what gives you more control over the execution of read functions.

5. Again super language dependent and not at all function coloring specific. Any language should either make the core libaris fully generic over the color, or provide both.

5.1. In rust all of core (and std) is gray/uncolored or blue. Read is in the end "just" layered on top and in core/std only supported as far as providing a (generator-like) code transformation and a view shared traits/utility types to allow impl. red context's as a library. If you consider such library a a core component of rust then rust has taken the path of providing a separate blue/red functions for all colored (non-gray) functionality.

So what is the takeaway? I would say the takeaway is that using arguments like "it's bad because of coloring" or well any argument using coloring as a reason why something is good or bad is fundamentally flawed. In the end it's not the coloring but the languages implementation of it which might or might not cause problems. This also means there are inherently more ways to fix a problem then there would be if coloring was actually at fault!