Nothing stops you from doing anything you want with threads, including using them to implement very safe patterns. The problems are, 1: the thread libraries do not afford those safe patterns, and indeed, afford very unsafe ones (and also ones that compose poorly) 2: libraries written for the ecosystem will end up using the poor patterns 3: lack of compiler enforcement and how easy it is to accidentally mutate something unexpectedly mean that unless you are superhumanly careful you will still screw something up, somewhere.
And you are correct that Go does not enforce shared-nothing between the goroutines. It has better affordances on those fronts that conventional C, but it is not enforced as it is in Erlang or Haskell. And while I say the affordances are "better", I still think that people screwing it up will be a practical problem.
Yeah, this is exactly right... I have to say Go changed my thinking about concurrency. But now I want to write a very small wrapper around pthreads that lets you write in the actor style. It just adds those "affordances".
Go is more or less the actors style, except with the (discouraged) possibility of sharing mutable state... even though for some reason it doesn't seem to be advertised as such.
The reason is that I don't think Go can cover what C + Python can. C gives you more low level control and Python is still shorter (and thus quicker). I like Go a lot but I would rather program in C + Python (like I do now) than C + Python + Go.
And then the other component to this is de-emphasizing the somewhat-horrible-for-concurrency Python/C API. The library I'm talking about would have channels, and you would have one end open in Python, and one end open in C. Python and C are running in different threads. Rather than the crazy subroutine/callback hell you have now with any nontrivial Python/C binding.
So basically I want to fix the C/Python interface, which is the only reason it is awkward to program in C + Python (the languages themselves are both great), rather than adding another language that overlaps highly with both of them.
The OS is written in C, so you've never going to get past C. If there was a whole world written in Go, that might be reasonable... but I don't believe in portability layers.
What does the OS being written in C matter? libc has to make a syscall to access OS functions just like anything else does. There's no obligation on a language implementation to make calls through C. It's a thin enough layer that if your language runtime is otherwise written in C you may as well, but that's a design decision.
It would be perfectly reasonable to write a non-C language runtime targeting Linux against syscall instructions or against Windows' documented system DLL interfaces.
Even if it didn't there's no reason to ever add a C dependency to your system if one of the languages you're already using has sufficient "systems" versatility. Go is clearly intended to fill this role.
tl;dr: you can get past C just fine even on an OS written in C and the C dependency isn't free.
Well, when you make a syscall, there's C on the other side. You can make a syscall without C, but it's not portable to different architectures. I think that is essentially the reason that every language runtime I know of uses C -- it's the only choice to portably access operating system services. If there is a counterexample that would be interesting to know, but I don't think it exists.
Probably Forth could be thought of an alternative non-C stack, and of course it's used on machines without an OS. But that's how far afield you have to go to get away from C.
My point is that when you're using Go your stack is still Go and C, to an extent. Usually you won't need to peek under the hood, but at some point when developing nontrivial services, you always need to. Basically my philosophy is that you should always understand at least 1 abstraction level below what you program in. With either Go or Python, that's C.
And you are correct that Go does not enforce shared-nothing between the goroutines. It has better affordances on those fronts that conventional C, but it is not enforced as it is in Erlang or Haskell. And while I say the affordances are "better", I still think that people screwing it up will be a practical problem.