
What Color is Your Function? (2015) - thinkloop
http://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/
======
miracle2k
See also this reply: The Function Colour Myth
([https://lukasa.co.uk/2016/07/The_Function_Colour_Myth/](https://lukasa.co.uk/2016/07/The_Function_Colour_Myth/)).

~~~
Shoothe
I don't see how this reply addresses the core point, it just argues that async
await is useful (that's fine but not novel by itself).

It is possible to work around the "color" by using generators [0], that way
one algorithm can be used in synchronous and asynchronous way. Async await
tightly bind to underlying Promises.

[0]: [https://curiosity-driven.org/promises-and-
generators#decoupl...](https://curiosity-driven.org/promises-and-
generators#decoupling)

------
skrebbel
I agree with the article but not with the editorialization in the title.

In the last 2 years I've mostly used Elixir and JavaScript. In Elixir,
generally all functions are synchronous. In JavaScript, there's the typical
two-color functions that the author describes: synchronous and asynchronous.

Elixir is nicer by far for a lot of parallel programming. Our backend can
handle large loads on a single VM simply because of this.

However, the _world_ is asynchronous. It's very nice that Elixir abstracts it
away, but sometimes that's not what you want and then Elixir makes things
significantly harder than JavaScript.

For example, imagine that my backend gets many parallel requests for mildly
different resources. Each resource needs to query some other system (some 3rd
party API, a DB, whatever), but it turns out that many of them will do
_exactly_ the same request to that other system even though the user requests
they're handling are all pretty much unique. A simple solution is to cache the
requests every second/minute/whatever and combine them all. This is nontrivial
because I want to cache the _running requests_ , not the responses. If there's
one request running, I don't want to launch an identical request.

In Elixir, I have to carefully design a GenServer to make this work properly.
Or maybe use a library such as the fantastic `memoize`[0] which is great for
this, and can even do it without spawning any additional processes at all. But
in any way, I have to add complexity - either complexity that I write or
complexity that I import. `memoize`'s core caching code is amazing, but not
trivial[1].

In JavaScript, I can just cache a bunch of promises in a Map or an object. If
the promise exists and hasn't expired, don't do a new request. Else, do the
request and cache the promise. Then, in either case, await the promise and use
the result. It's 10 lines of boring code.

I still like Elixir better for backends and I'm happy that our backend isn't
Node. But I'm writing this to underline that explicit support for
asynchronicity can be a feature too.

[0] [https://github.com/melpon/memoize](https://github.com/melpon/memoize) [1]
[https://github.com/melpon/memoize/blob/master/lib/memoize/ca...](https://github.com/melpon/memoize/blob/master/lib/memoize/cache.ex#L94)

~~~
he0001
> However, the world is asynchronous.

Can you give me examples of sources that explains this concept? I really don’t
think the world is asynchronous, because if it were the Big Bang could happen
now. Aren’t you mixing the word ‘asynchronously’ with ‘independently’?

~~~
Someone
Have you been staring ahead mindlessly for the past hour, blocked while
waiting for an answer, or did you do something else?

I’m not the one making the “the world is asynchronous” claim, but I think this
is what (s)he ment: in the real world, there is no “make a request and wait
for an answer, doing nothing at all until you get an answer, even if one never
comes”.

That need not be true, though. One could model the human brain as a blackboard
with N cores, each running a single process (one for breathing, one for your
heart rate, etc), and one of those cores blocking forever on such a question,
with a “OOT killer” killing a low priority thread when needed. I wonder how
one would go about falsifying such a model…

~~~
he0001
Waiting for your answer pretty much was like that, and yes I did a lot of
completley unrelated stuff. I don’t think computers model the “real world”
pretty well. Though they can model a lot of other things very well. The real
world isn’t asynchronous, it’s continuous with something seemingly unrelated.
If this world were asynchronous, there would be an possibility that I would
have given this answer before you gave me an question. Where are the
synchronizing primitives in the world making sure that this never happens?

~~~
inyourtenement
Could you define synchronous and asynchronous as you understand them? Because
I don't think your definitions match the rest of the people in this thread.

~~~
he0001
”The primary focus of this article is asynchronous control in digital
electronic systems.[1][2] In a synchronous system, operations (instructions,
calculations, logic, etc.) are coordinated by one, or more, centralized clock
signals. An asynchronous digital system, in contrast, has no global clock.
Asynchronous systems do not depend on strict arrival times of signals or
messages for reliable operation. Coordination is achieved via events such as:
packet arrival, changes (transitions) of signals, handshake protocols, and
other methods.”

[https://en.m.wikipedia.org/wiki/Asynchronous_system](https://en.m.wikipedia.org/wiki/Asynchronous_system)

~~~
Someone
The thing being discussed is
[https://en.wikipedia.org/wiki/Asynchronous_method_invocation](https://en.wikipedia.org/wiki/Asynchronous_method_invocation):

 _”asynchronous method invocation (AMI), also known as asynchronous method
calls or the asynchronous pattern is a design pattern in which the call site
is not blocked while waiting for the called code to finish. Instead, the
calling thread is notified when the reply arrives.”_

~~~
he0001
Uh, no. It was about if the world is asynchronous or not. I don’t have much to
say about OP, but the “world is asynchronous” usually comes up in these
discussions. I think that’s really wierd and wanted more info about it since I
haven’t yet seen a convincing explanation about that.

~~~
inyourtenement
You're just misunderstanding the claim. People mean something like "most
things in the world operate in a non-blocking manner". It's not some deep
claim about the universe.

~~~
he0001
In this case perhaps, but it usually becomes some sort of deep claim of how
the universe work. And I do think asynchronous computer execution is not even
close to how the world operates, so it’s not even a good metaphor.

------
littlestymaar
This article has already been posted 3 times on HN, and have been extensively
discussed the first time here:
[https://news.ycombinator.com/item?id=8984648](https://news.ycombinator.com/item?id=8984648)

------
throwaway13337
Async web servers are more complex than thread per connection ones.

I think that's the big thing the author is communicating.

It's true.

And most types of development don't need async io. It's worth talking about.

The author makes the mistake of calling this a language problem and not a web
server problem.

With python, Java, c#, and hell, even js, you can have a thread per connection
web server if you choose to. This will avoid many async woes.

It's just not trendy.

~~~
xtrapolate
> "It's just not trendy."

The "thread-per-connection" model doesn't scale. It's simply not resource-
efficient in any way.

~~~
terminalcommand
As far as I know Golang uses the thread-per-connection model.

Furthermore, in languages such as Erlang having an actor-based model, there
are thousands and thousands of microthreads.

I think if you use lightweight threads (green threads, goroutines, etc.), the
model does scale.

~~~
sudhirj
Lightweight threads don't count as real threads - that's a different
concurrency model that may or may not map to actual OS threads.

In Go, for example, I don't think OS threads are used at all, just processes.
You can set GO_MAX_PROCS=1, for instance, and have all your goroutines running
on a single process, effectively making it a single threaded system like Node.
In that scenario, you're back at cooperative scheduling, because control will
only transfer to another goroutine if you delegate to a runtime call or call
os.Gosched() which is an explicit sleep + control transfer.

~~~
sudhirj
This is actually a viable deployment strategy for Go programs, with a few
people recommending it. The advantage is that your code cannot possibly have
race conditions, even as it works with any number of goroutines. To better
utilize multicore hardware, you'd use something like
[https://github.com/stripe/einhorn](https://github.com/stripe/einhorn) to
share the incoming socket with as many Go processes as you have processor
cores. Since Go's memory footprint is so low, this is actually a pretty decent
way to do things.

------
hyperion2010
Just the other day I was looking over my notes from (horror of horrors) 3
years ago on core problems to avoid when designing a language, and this
article came up. Still just as good a read as I remembered, made all the more
pertinent by the intervening time in which I have repeatedly cursed python's
implementation for the massive friction burns it has caused me. Probably needs
a (2015) on it for context, but I consider it timeless!

------
mcv

      > Wanna know one that doesn’t? Java.
    

Unless you use Vert.x of course.

A year ago I helped a friend on a big project in Java for which he was using
Vert.x. Suddenly I find myself doing Javascript-style programming in Java.
Convenient for calls to other services (a payment provider, for example), but
indeed a bit cumbersome if you're used to Java being synchronous.

------
wokwokwok
Please add a 2015 tag, this is old and has previously been extensively
discussed.

------
kabes
Fibers (coroutines) solves most of the criticism for JS. Although not part of
the language and you need to extend v8, it's a viable option for webservers. I
believe that's how the Meteor framework has been doing it years before
async/await or even promises was a thing.

------
egnehots
And a great sage would say that it all boils down to category theory.

