For me, Go misses the sweet spot entirely. A year ago I was curious about both Go and Clojure, my interest piqued by the strong concurrency support each has. I picked Clojure and have grown more and more confident in that choice.
Why not Go? In a language with nil pointers (Tony Hoare's "billion-dollar mistake"), no generics, and sub-JVM performance, static typing just doesn't seem worth it. Also, poor interop with other languages means Go can only draw from its own small community for libraries (contrast Clojure which makes using mature, well-tested Java libs trivial).
When Rust is more mature, it may be what I hoped Go would be: the safe language, with lightweight threads, that makes me never have to write C or C++ again.
Go is interesting and I really enjoyed channels, but no generic programming really disappointed me. I guess supporting the generic paradigm is pretty tricky (C++/Java templates/generics aren't dear to my heart), but not being able to implement map/filter/reduce functions...
My main objections were neither performance nor reliability (I don't care about either while prototyping), but developer productivity. I find there are just so many programming conveniences in Python that I wish I had in Go - list comprehensions, negative slice indexes, for- and with-statements over user-defined data types, heterogenous dictionaries, easy duck-typing. When I just want to get some ideas working to prove a concept, it's really annoying to flesh out all your types and error handling in full detail.
I do think Go would probably make a pretty nice production language, but I'm not at liberty to convert the large C++ and Java systems I work with to Go. Even if I were, I think I would prefer C or C++ because of its easy Python bindings.
Any reason why doing this with channels and goroutines doesn't fulfill your requirements?
Except that you do. You've just said it yourself! What the for command does in Python is essentially running two communicating coroutines, passing control between them. Yield-using generators actually make it very explicit, by creating special resumable stack frames. The only difference is that in Go, you're not limited to a single stack frame in the producer, nor do you have to use a loop or the new PEP-380 "yield from" syntax (for example, if you're iterating over a tree). The blocking channel takes care of the execution sequencing. (Also, in Go, the channel makes it possible for the consumer to use multiple stack frames, if you're re-building another data structure instead with the data you receive from the producer, but that seems to be a rarer case. It's a nice symmetry, though.)
Basically what I wanted this for is that I have a user-defined type that is basically a list of some other user-defined type, plus some extra stuff. In Python it's trivially easy to implement __iter__ and delegate, and then I could manipulate these objects the way I thought of them, as containers for other objects. In Go...I wonder if I could've used type embedding (making the first member of A be []B), but I don't think the built-in language constructs respect embedding when figuring out what's a legal expression. I ended up biting the bullet and explicitly looping over the slice member, but the point of prototyping is being able to think of your code in the terms of your problem domain.
I played with Go in the beginning, mainly due to the Pascal and Oberon feeling the language has. Even tried to submit some code back to the project.
Went back to C++, .NET and Java, with an eye on D and Rust, because:
- Most Go features are actually not that new, if you happen to have a good CS background with lots of experience in many programming languages
- The community attitude "our way or the highway" regarding generics, error handling, dynamic libraries and package management
On the other side is things like Python, which are reasonably good for a much lower fraction of things (e.g. 30%), but if you're in the 70% you very well might not realise it does not suit your situation and thus experience Python stinking.