I disagree. Some features are more complex than others and design has little to do with that complexity.
Async is a good example of a complex feature that needs a fairly detailed blog post to understand the nuances. Pretty much any language with coroutines of some sort will have 1 or many blog posts going into great detail explaining exactly how those things work.
Similarly, assuming Rust added HKT, that would also require a series of blog posts to explain as the concept itself is foreign to most programmers.
Languages using pure versions of the pi calculus support concurrency without any of the usual headaches.
Async is a great example of this problem. It is way more cumbersome in Rust then it could be, in a different universe where Rust concurrency made different choices.
> A properly designed feature shouldn’t require an entire blog post, let alone multiple, to understand.
After reading though the wiki about pi calculus and looking up the few languages that support it, I would be pretty shocked to find a language that adds a pi calculus feature wouldn't need several blog posts explaining what it is and how to understand it.
It's a stretch to argue that Go's concurrency model is pi calculus. Go supports lexical closures, and even the initial body of a goroutine can close over variables in the parent scope.
Go's concurrency model is fundamentally lexical closures[1] and threading, with channels layered on top. Lexical closing is, afterall, how channels are initially "passed" to a goroutine, and for better or worse it's not actually a common pattern to pass channels through channels. And but for Go hiding some of the lower-level facilities needed for thread scheduling, you could fully implement channels atop Go's lexical closures and threading.
I think the similarity to pi calculus is mostly coincidence, or perhaps convergent evolution. The choice not to make goroutines referencible as objects, and the fact channels can be communicated over channels, makes for a superficial similarity. But the former--lack of threads as first-class objects--comes from the fact that though the concurrency model is obviously threading, Go designers didn't want people to focus on threads, per se; and also it conveniently sides-steps contentious issues like thread cancellation (though it made synchronous coroutines problematic to implement as the GC has no way to know when a coroutine has been abandoned). And the ability to pass channels through channels is just consistent design--any object can be passed through a channel.
[1] Shared reference--non-copying, non-moving--closures. Though Go's motto is "share memory by communicating" as opposed to "communicate by sharing memory", Go comes to the former by way of the latter.
Just to add, Go was inspired by Hoare's CSP paper [1]. Hoare came up with the ideas of CSP separately from Milner [2] even though they have some cross over concepts. The two collaborated later on, but really had somewhat independent approaches to concurrency.
To respond to the OP. Go's concurrency model absolutely has multiple blogs written about it and explaining how it works. It's actually a little funny OP was thinking Go was based on pi calculus when it was actually based on CSP. That goes to my original disagreement. Good features need explanation and they don't become "bad" just because they require blog posts.
Do you even know what the pi calculus is? Like, you can implement the pi calculus (or the lambda calculus) by explicitly rewriting names but that's rarely done in practice. Any practical implementation would have a set of channels possibly shared by different processes and that's not very different from the free threading model with channels. By disallowing any other communciation methods you effectively end up with the actor model, was this what you were arguing for?
Async is a good example of a complex feature that needs a fairly detailed blog post to understand the nuances. Pretty much any language with coroutines of some sort will have 1 or many blog posts going into great detail explaining exactly how those things work.
Similarly, assuming Rust added HKT, that would also require a series of blog posts to explain as the concept itself is foreign to most programmers.