So, you're right, but it has been addressed.
Since you're asking, Rust's ownership/type system, for example, has checks in place that prevent at least some classes of concurrency errors.
For example, you can't directly modify a variable from multiple threads, due to the so-called "move" rules:
let mut myvar = vec![];
thread::spawn(move || {
myvar.push(1);
});
myvar.push(1); // can't do this; variable has been movedIn other langs I'd expect to see this code use a generic map-reduce/parallel map helper function or something like that, but in Go people seem to be happier writing for-loops and spawning goroutines by hand every time.
Concurrency is hard, and one fairly successful approach is to provide battle-tested libraries for these high-level use cases (“run M functions with max parallelism N”). Go gives you low-level concurrency tools, but actively resists the kind of abstraction that would let you make reusable high-level tools, so that robust library doesn’t exist.
It’s a strange lack, as it’s meant to be a concurrency-focused language, and the standard library is absolutely terrific in other areas (eg networking and encryption).
Like some other comment here says, you run into bugs like this early on and they're not necessarily show-stoppers. Maybe keeping the language simple and ensuring that most code is readable if you only know the language and the stdlib (and not some fancy concurrency library) is worth the occasional bug?
Of course that doesn't necessarily mean that Go is the language I want to use for every use case under the sun, but that probably wasn't a goal of Go to begin with.
That's a tautology though :) Of course any language designer will design a language according to the properties he/she desires.
> you run into bugs like this early on
Not necessarily. Race conditions are hard to find. It's established that "simplicity" is not a straight forward metric to measure. Having a simplistic language just means that complexity is being pushed on the programmer, since most non-trivial programs are complex by definition.
Regardless of what the goals of golang were (they kept changing their definition of "systems language"), the fact that it's being pushed for almost everything, due to hype and fad driven development, and the inexperience of many programmers, is an issue. It's almost ironic that golang is used more outside of google than in.
Eh, you can just fail, too, no? Like I could sit down and set myself the goal of designing a language that achieves goal X while staying under complexity limit Y (by whatever measurement), and then end up having to compromise on either of them because I can't quite figure out a good way to achieve a particularly tricky part of X without adding a lot more complexity than I initially expected. Or I could decide I want to design a language that's portable across many CPU architectures but inadvertently bake in a lot of x86isms that make it awkward/inefficient to implement elsewhere.
> Not necessarily. Race conditions are hard to find. It's established that "simplicity" is not a straight forward metric to measure. Having a simplistic language just means that complexity is being pushed on the programmer, since most non-trivial programs are complex by definition.
Ah, I didn't mean that concurrency bugs are quickly found or solved. I definitely agree with the just-moving-the-complexity-around part. I just meant that soon after getting started with Go, you'll probably have run into a bunch of concurrency bugs already and developed the kind of mental scarring and automatic averse reactions to certain concurrency situations that'll let you cope and still get things done despite it being clearly suboptimal.
> the fact that it's being pushed for almost everything, due to hype and fad driven development, and the inexperience of many programmers, is an issue.
But this is a kind of success too, isn't it? Presenting your solution to a problem in a way that appeals to enough "inexperienced" people to create the hype/fad isn't trivial, so they must have been doing something right. I don't think it's just a case of "$bigcorp does it, so it's cool", plenty of $bigcorp languages or technologies don't really catch on, let alone on Go's scale.
I think there really is a niche where Go is the best solution (or at least a significant local maximum), even if that is only "'inexperienced' programmers can get started with, say, highly concurrent http services", it's still _something_.
(Again, disclaimer: I use Go at work and I like to give my (non-google) employer and my coworkers enough credit to think that it's not just because of hype/fad, so I may be biased.)
Yes, other languages provide you with more tools than the basic nuts and bolts. For example a language might provide you with a "parallel for" primitive that is well tested.
The issue is not exactly that Go's concurrency stuff is bad, it's just that it doesn't give you much help so you have to implement it all yourself. Also the lack of generics means it is difficult to write libraries for this stuff.
Search for "race condition", or just "race".
This section in particular is about preventing data races: https://docs.adacore.com/spark2014-docs/html/ug/en/source/co...
This one is about preventing race conditions: https://docs.adacore.com/spark2014-docs/html/ug/en/source/co...