I actually agree with the people who say that the lack of generics is serious. It prevents people from writing general-purpose libraries, or at least makes it harder. That said, there are many decisions the Go team made that I respect highly. Go is a language made for Google. It solves many large-scale production problems extremely well, and its concurrency model is neat as well. (I’d prefer to use Clojure and core.async, but that’s just me.)
I’ll give you a hint, which is that there’s nothing wrong with the language. The problem is that we do a piss-poor job of understanding what it is we expect from programming languages right now, at least members of the pop-software culture (myself included).
Agree whole-heartedly. The quality of a programming language is impossible to assess independent of the context in which it is to be used. I understand that people are generally infuriated at having to use underpowered languages (say, Java) at their jobs and, worse yet, the shitty tools and design principles that often come with contemporary OO, but it’s not Go’s job to liberate them. No language right now does everything perfectly, and that “one language to rule them all”, risk-averse-businessperson, type of attitude (that immature engineers often cop) is the real enemy.
It solves many large-scale production problems extremely well, and its concurrency model is neat as well. (I’d prefer to use Clojure and core.async, but that’s just me.)
One thing to note here, I believe it was Rich Hickey or perhaps Timothy Baldridge who pointed this out at Clojure/conj 2013: “I wouldn’t want to use any language that only had a single concurrency model”, to paraphrase. This came up during a core.async discussion and I think it’s a really good point to make.
Consider that while CSP-style concurrency is clearly suited to many problems, you still need to be wary of deadlocking the parent thread. This implies that certain tasks should not happen on the logical threads provided by Goroutines or inside go blocks in core.async, e.g. blocking IO.
A related problem is that when you’re given a lens with which to see the world through, you start to see all your problems in terms of that framework; if given a hammer, suddenly you see nails everywhere. So in the case of CSP and Go, the danger, I think, is that then you start to shoehorn all your problems into what Go is capable of. Whereas a language like Clojure gives you the same capabilities in terms of concurrency model, but also allows you to do what you want by way of providing additional models for concurrency and being flexible enough for you to do essentially whatever you want.
I’m not sure, but I think blocking IO inside a Goroutine isn’t much of a problem because IO calls cause the current goroutine to yield. At least, I would be incredibly surprised and disappointed if this were not the case.
I don’t know the precise details of how this is implemented in Go, so I’ll explain the problem from the Clojure core.async perspective, where it is well known that blocking tasks should not live on logical threads. I believe in the case of Clojure, assuming you’re on the JVM, there is a thread pool. However, imagine you’re doing a lot of blocking IO, on the order of thousands of logical threads. Ultimately, the thread pool is starved and you’re blocking on the logical threads. This causes the parent threads to deadlock.
I would be curious to know if Go has some mechanisms around preventing this? Perhaps even the Clojure implementation does which I’m misrepresenting here. However Timothy Baldridge has said on numerous occasions that you should not do long-running or blocking tasks in logical threads, instead you should use real threads for that. Otherwise you risk deadlocking and strange performance outcomes.
Edit: Here’s a pretty decent blog post talking a bit about this issue in Clojure.
However if you are using go blocks and blocking IO calls you’re in trouble. You will in fact often get worse performance than using threads (in the normal case) since you will quickly hog all the threads in the go block thread pool and block out any other work!
Go’s scheduler and it’s IO stack are tied together to prevent IO from blocking goroutines. It’s something Clojure cannot due because the JVM’s scheduler is not under its control.
I was waiting to see who would write this article. We as a team have been discussing the rants we’ve seen come up about Go, and this article perfectly echos what we’ve thought internally. Basically, if you know it doesn’t do what you need, either patch it to do that (as you’re probably not the only one that wants it), or go to a language that does support your needs.
Indeed. Every article I’ve skimmed over has matched what this guy said. I’m not sure why everyone is so hung up on generics. Somehow I’ve managed to write millions of lines of code in my career and the generics problem is so foreign to me that I don’t even know what it is ;) On a related note, people need to quit trying to solve every problem with a design pattern when a few simple functions will work. I built a relatively full feature processing application that some OO architect got his hands on. It went from a few hundred lines to process a file to several hundred classes and thousands of lines of code… oh, but it’s OO so it’s better. Not to mention harder to read, update and maintain. Why people don’t look at code from a “how-is-this-going-to-be-maintained” standpoint when developing I’ll never know. It’s the longest phase of the software lifecycle. Anyhow, grumpy guy is right. :)
I think lots of people get hung up on generics because they didn’t really think about what they were going to build, just that they wanted to try out Go. Because they weren’t entirely sure what they wanted to do, they probably tried making some data structures, which are difficult to do “correctly” without generics.
Basically they didn’t look into the language, they just heard that people liked it, and wanted to try it out.
Somehow I’ve managed to write millions of lines of code in my career
I know I shouldn’t take you literally, but it got me to wondering… How long would it take a great programmer to write one million lines of code by themselves?
The LoseThos/TempleOS says
I wrote all 121,378 lines of TempleOS over the last 10.4 years, full-time, including the 64-bit compiler.
So maybe 85 years. I’m not sure if the schizophrenia helps or hurts.
Here’s an article that talks about the cost of re-writing a million lines of code. Enough to sink a company, apparently.
“write” but lets not forget that I did java so you get about half way there with your xml configs. By the time you finish those and apply a design pattern you’re close to 100k ;)
The article is a long winded version of “If you don’t like it, you can get out.” Isn’t it entirely possible Go is used for its other features except the lack of generics, but now people aren’t allowed to complain?
Out of commonly used languages, the only ones lacking generics is C and Go. Most Go users are transitioning from higher level languages and thus accustomed to generics. They don’t understand why generics aren’t available since Go uses generics internally and there’s no obvious tradeoff.
A lot of the complaining has undertones of “you’re having fun writing Go and I don’t like it [the fun you’re having], so you need to stop.” A blog post like “I built a whizbang and used python because go didn’t suffice” would be more positive than “go is not the solution, even though I haven’t identified my problem yet”.
Yeah, I get sad every time I tell someone “I finally enjoy coding again.” And they’re so bitter and jaded about their current situation they have to rain on your parade.
Out of commonly used languages, the only ones lacking generics is C and Go
You’re right. I wouldn’t mind generics on Objective-C, though.