> Everything [in Smalltalk] already is a message being passed, and so the difference between asynchronous and synchronous message should be very minor
But this seems to confuse paulhodge's #2 and #3. Messages as first-class values don't give you asynchronous messaging for free. Or do you just mean that syntactically the async code would look like normal sync code? That's true of JS as well, of course, and it's a problem. Async vs. sync is a fundamental distinction for the programmer, and one wants help to keep track of what's going on. I suspect Erlang got it very right in having two lightweight but distinct notations for these two deeply distinct things. What other languages do that?
Edit: It occurred to me that you said something profound:
> For me, in Erlang code, function call is about 'here', while sending a message is about 'there'.
"Here" vs. "there" is a spatial distinction; "sync" vs. "async" is a temporal one. The temporal distinction is far harder to get one's (my) head around, perhaps because code itself is laid out spatially, so you constantly have to recreate its temporal model in your head when you read it, and that's taxing. It's far easier to think of code as divided up spatially. We build up a system by making repeated 'inner' vs 'outer' distinctions - i.e. modularity. That structure is static while the temporal structure is dynamic and unpredictable. To write good async code you have to get in the habit of thinking "who knows when". But you never have to think "who knows where". The code tells you where.
This makes me think that there is wisdom in Erlang's decision to identify the temporal distinction (sync vs. async) with a spatial one (inside a process vs. outside it) — thus guaranteeing a translation from the harder mental category to the easier one — and to provide distinct notations for there-and-async vs. here-and-sync, so you always know which is which. Total complexity seems greatly reduced this way compared to a model in which the two distinctions are orthogonal and can combine in arbitrary ways.
For Erlang to say that between objects (i.e. processes) things are async and pass messages, while within an object they are sync and call functions, is a major departure from the Smalltalkian "everything is the same everywhere" small-and-regular philosophy. I'm fond of small-and-regular designs, but sync vs. async is one of those distinctions that is so fundamental, it's folly not to have it in the core unless you intend to get away with pretending that everything is always synchronous.