I think this is part of it, some of the hate comes from people that "know better" (possibly true for some, obviously the Go authors aren't omnipotent) than the Go language designers and are baffled that the language design ideas they know about aren't in the language.
But I can tell you in my experience that this type of forceful "everything is a error, no warnings" and "it is done this way (formatting for instance)" are a breath of fresh air. Having dealt with team members that barely know how to program and think a compiler spitting out an executable means it's ready (what warnings? why do those matter, it compiled), Go makes coordinating with them a lot easier. It forces them to be more correct before an executable is created. It doesn't make them better, but at least the rest of the team can work with what they create until they do get better.
Also, the simplicity of the language sure helps everybody (regardless of skill) get up to speed quickly. People that know what they're doing may hate there isn't some special feature they love (generics, etc) in the language, but working with a team of varied skill is so much easier this way.
In before "but adding generics does not make team projects harder, look at language ..."
What I like about strongly opinionated languages in general is that most of the strong opinions are around trivial features of the languages relative to the complexity of a decently interesting programming problem.
Features like formatting, no unused imports, etc.
These are typically areas in a project where Parkinson's Law of Triviality rears its ugly head in project planning meetings. Everyone feels the need to bloviate about 2 vs 4 indents, tabs vs spaces, or which lint flags to enable/disable.
Hell, with go get always grabbing the master branch, it even implicitly requires projects to keep their master branch 'green' so it doesn't break projects that depend on it. A very neat way to eliminate a whole set of "Which branching model should we use?" arguments.
I'd also say that many of these things are trivially fixed in other languages using tools. Most big projects have some code style guidelines which can be enforced using a linter and any good Java IDE can auto-clean imports lists for you at commit time (IntelliJ can be configured to auto-optimise imports just before commits for instance).
Making the compiler super strict about it seems like a good way to make quick changes awkward. Especially when there isn't a strong debugger you often end up commenting bits of code out or adding "return true" type statements half way down functions, and it's annoying when the compiler refuses to let you do it. This is one of the things that bugs me about javac - if it detects dead code in a function it refuses to compile. Maybe I'm weird but in my work this has caught legitimate dead code exactly zero times, but has triggered false positives due to transient debugging changes eleventy bazillion times. Luckily javac is dumb and you can trick it by just writing the code as "if (true) return;"
It is illegal for a package to import itself, directly or indirectly, or to directly import a package without referring to any of its exported identifiers.
>These are typically areas in a project where Parkinson's Law of Triviality rears its ugly head in project planning meetings. Everyone feels the need to bloviate about 2 vs 4 indents, tabs vs spaces, or which lint flags to enable/disable.
It was in one of the numerous Go talks/videos/presentations where I think it was Ken Thompson who said that he could walk around the Google cafeteria and hear Python programmers arguing all day long of how white space should work, and in Go, those discussions just don't happen. It's done. It's been decided. Move on.
It really struck a chord with me. It's amazing how smart people, given enough free time, will argue non-stop about the most irrelevant, insane things and stop themselves from being productive.
I disagree with you here. First, just because people are arguing about irrelevant insane things doesn't necessarily mean they're not productive. Second, I love those trivial arguments because at the end of "lunch" I've taken a break from the more involved thought, floated up to lighter stuff for a while, had some fun, and can now easily get back to the tasks at hand.
I agree with a lot of these (and would be interested in adopting a language that followed them - but one with a decent type system), but I don't think that's the Go innovation. Python had opinions about whitespace and never attracted the same level of hate.
Python's long in the tooth right now, but the first few years the whitespace thing was the source of much cursing and gnashing of teeth.
edit
More to your point, though. I would never choose a language for a project because it is strongly opinionated on such things. However, when choices lead to an opinionated language I find the feature a positive rather than negative edition....even if I find a particular decision annoying at first.
Python's whitespace has arguably produced metric tons of heated discussion on the net since Python's inception. Back in the day it was often the main thing outsiders (jwz comes to mind) rejected.
I think Python's mandatory whitespace has a similar nature as Go's unused-as-an-error. They are definitely great in production code, but when I play with code, sometimes I do want to mess them up while adding and removing the parts of the code. Even though I've used Python for more than 10 years, I often feel like "I don't want to indent these lines for now. I wish there were a way to wrap them up without changing the indentation" after copying and pasting some lines.
But then again, unfortunately, Python's significant whitespace makes automatic indentation hard, because there are some edge cases that an editor cannot extract the actual intention by the programmer well. For example, if there is a code as:
for i in range(10):
if i % 2 == 0:
print('hello')
and I paste `print('world')` after that, there are at least three possibilities of the proper indentation of the line. It can match with `print('hello')`, or with `if`, or even with `for`.
That's because Python encodes block information solely using whitespace. So, if the indentation changes, the actual meaning of the code also changes! In fact, that's why it is called "significant". You cannot automate it, just like you cannot automate writing code.
> features like formatting, no unused imports, etc.
I personally think these should be configurables turned on by default so you kind of push the new comer to write good code and build better habits but there should be an option to disable it, make it hard to find but it should be there, especially for the people like OP and other small over-the-weekend projects.
The goimports tool can be used to automagically add and remove imports to your .go source files as you work. This streamlines the casual weekend hacking use case without compromising on the benefits of disallowing unused imports.
In before "but adding generics does not make team projects harder, look at language ..."
Your (and many other people's) insistence on dismissing discussion regarding generics as some kind of a joke is anti-intellectual. You're rejecting valid criticism of your arguments on the basis that the critic's argument is unworthy of attention for some reason external to the discussion at hand.
I agree that pro-generics arguments are usually boring, and at least 90% of what they say has been heard before. But the same can be said of Go evangelism, like your comment; they are no less worthy. Please don't deliberately shut down discussion.
I don't even get the vitriol against generics - the designers have only taken a "not now" approach to the subject and everyone acts as if Go is a social experiment to get everyone mad about generics.
Then people bring Rust, which has only had a stable grammar for last couple months and a standard library nowhere near Gos. Would it be wise to complain that the Rust stdlib doesn't contain a HTTP server implementation?
It's not just the "not now" approach. It's the rhetoric that often goes along with it. The author of this piece picks up on it when he talks about the "we've already thought about this and we're tired of talking about it" vibe, though I might characterize a lot of the discussion around generics from the Go community at large more specifically as "you think you want/need this, but trust us, you don't, and the inconveniences you think you're experiencing are just not that big a deal, particularly compared to the inconveniences you'll experience if we do add it."
And yes, if not having an HTTP server implementation in the stdlib seems like it makes your project difficult, that's a perfectly reasonable criticism of Rust.
(Though one I suspect will get resolved much more quickly and cleanly than issues like generics in Go.)
> I suspect will get resolved much more quickly and cleanly
It's pretty easy. You just add this line to your Cargo.toml:
hyper = "0.3.14"
And the next time you build, Cargo handles everything. You can now use hyper like any other library that's included with Rust, no biggie.
This is one reason we've chosen minimalism for the standard library: It's really easy to use external libraries, and once things land in the standard library, they often don't improve much. The versions become tied to the compiler versions, contributors now need to build the entire compiler rather than just working on a single library, and everything else. We've already seen three distinct major HTTP implementations happen, had we put rust-http right in the standard library, we'd have frozen something the author has already deprecated!
Choosing non-minimalism has advantages too: in this scenario, you need to know that hyper is currently the best library, for example. Engineering is all about trade-offs.
(Solely chiming in on the HTTP in Rust thing here. I found the part of the article about the Gopher... lacking, and it distracted me from the rest of the author's points.)
no. there is a HUGE difference between std lib and third-party libs. Std lib is like a contract - maintainers of language have to keep all parts up to date and working. Maintainers of third-party library can write "Farewell Rust" blogpost and all projects, based on that library will be in trouble. And as http is a very important thing for web-programs, it's much better to see support of http in std lib.
> Std lib is like a contract - maintainers of language have to keep all parts up to date and working.
Rust has language stability (in practice right now, and officially once we hit 1.0 in a month), so we in fact do guarantee this.
> Maintainers of third-party library can write "Farewell Rust" blogpost and all projects, based on that library will be in trouble.
Languages can do that too, in which case the entire language and its ecosystem is in trouble. Anything can be abandoned. The crucial thing is that if a piece of infrastructure is in the standard library, then it's much harder and slower to iterate on it. HTTP is a fast-moving standard (see HTTP 2, for example), and so it's very important to be able to iterate quickly to support new features.
> And as http is a very important thing for web-programs, it's much better to see support of http in std lib.
I disagree. Web applications need HTTP, but many applications aren't Web applications. As a example on the far opposite end of the spectrum, your OS kernel doesn't have an HTTP stack in it (unless you happen to be running something like khttpd), and Rust is designed to be usable for OS kernels. Large standalone standard libraries reduce flexibility, and Rust is designed to be flexible.
Hmm... Windows has part of a HTTP stack in the kernel, which I know solely based on hearing about the recent vulnerability in it. And OS X's kernel, IIRC, can load disk images over HTTP for netboot purposes. That leaves Linux as the odd one out :)
(Yes, I know that's completely tangential to the point you're making.)
Languages can abandon own std lib? Keep away from such languages.
> HTTP is a fast-moving standard (see HTTP 2, for example), and so it's very important to be able to iterate quickly to support new features.
Golang doing it just fine, so Rust can too.
> I disagree. Web applications need HTTP, but many applications aren't Web applications.
I'm talking exactly about web applications, not about all applications. And if web applications is not the field of Rust - let us know about it. Right now is not obvious and even web frameworks exist in Rust.
Languages can abandon own std lib? Keep away from such languages.
Not abandon their stdlib. Be abandoned. There is nothing more preventing developers of the compiler/vm from abandoning their efforts than the developers of a library. It would make little sense for developers of the language to abandon just the stdlib, as it is part of the language.
I'm talking exactly about web applications, not about all applications. And if web applications is not the field of Rust - let us know about it. Right now is not obvious and even web frameworks exist in Rust.
Rust is a fine language for web applications, but it's not designed specifically for them. The languages with huge stdlibs date from a time when accessing libraries was much harder than it is today. The internet, as well as package management, was young when Python and Java were born. Now that it's easy to download packages, and we have reasonably passable tools for doing so, there's no need for heavy standard libraries.
Go is specially designed for running on servers and performing network tasks. So it makes sense that it would have a stdlib with rich networking support, including http.
Node was designed as a frontend to libuv, to make nonblocking IO easier to use. The most visible domain where nonblocking IO is extremely useful is in making web applications, AND the fact that it's javascript makes it even better suited to web. So Node has http support baked in.
Rust is meant to exist in the same space as C++. It can be used for anything. OS kernels to text editors to web applications. There is nothing in particular that ties it to any of these domains. It has the option of putting support for all of these in the standard library, which would make it hard to maintain. Every time one part of the stdlib needs to change, the language needs a minor version bump, or there's a delay before anyone can use the new libraries. Not a big deal when you only have one or two domain specific components in the stdlib, but a problem when you have twelve.
If the stdlib supported only some specific domains, it would give people from other domains the impression that they're second class, and drive them away. Not cool.
Language can be abandoned, but it's pointless argument, sorry. When language is abandoned, there's no reasons to argue about any aspect of that language.
In second part of your comment you comparing stdlib and external libs as they are equally reliable, but my point is exactly about difference in this aspect. I agree stdlib shouldn't be swiss knife, but I disagree it shouldn't have nothing except minimal set to serve language constructions. Go was designed as C++ also, not only for networking. And it has image module, not only http (for example). I see how fast and successfully Go evolving, I think Rust is better and that's why I think it's the area where Rust can take better idea from Go.
I would argue that Rust's approach is perfectly fine so long as they have strong organisational support around third party libraries. Look to Java for how to do this. Many core Java libraries are managed by Apache or Eclipse e.g. HTTPClient who manage the process around open source projects.
HTTP clients are not something I would want in a standard library to be honest. Since there are so many different ways to implement them. And not all work for all use cases. It's not the same as StringUtils or ArrayUtils.
Why not let a bunch of third party HTTP libraries pop up. Eventually things will converge on the "best" library for doing http in rust. Open a discussion and start adding great third part libraries to the std lib. The challenge then would be keeping this coherent throughout the std lib.
Not sure why you think I don't want to let libs pop up. I just ask for http module in std lib, not as the only implementation which can exist, but as "last resort", always working, in any new version of language, supported and tested by core team maintainers. Not full-featured thing with routes and other whistles and belts, just basic things.
Haskell does it the way Rust does and it's pretty frustrating to have tons of solutions to evaluate for everything you want to do. Maybe crates.io will have a better discovery story, or rust will have a larger user base that makes it more likely that there's a clear winner. I hope so.
> I don't even get the vitriol against generics - the designers have only taken a "not now" approach to the subject and everyone acts as if Go is a social experiment to get everyone mad about generics.
I don't use Go so I don't really care about their generics or lack thereof. What I found ... odd ... is how the Go team has apparently said they can't go generics because there's no good way to implement them. Seems like a strange thing to say when many languages are happily using them.
Implicit interfaces make generics a lot less trivial to implement. They also don't want to simply add an existing approach with bad trade-offs (see C++ templates). Likewise, adding a runtime based multi-dispatch based generic system is not much better than what we already have.
Lot's of languages have generics, but they have trade-offs, so they aren't free, even if they can implement them using existing generics implementations. Picking what they're willing to sacrifice can be hard, even if it's something like slower compile times.
Anything backwards compatible has to be in Go 2 or later, because generics are hard to make backwards compatible, we'll have to wait.
After hacking Rust, I got the feeling that generics are hard. They are so hard that a language should consider them from the beginning to fully take advantage of them. That might be the reason why the Go team says generics are hard to implement in the current Go type system. They can also choose either C++-like code generation based on templates, or external code generating tools, but both are not perfect in my opinion.
And library can be easily abandoned or just be broken after breaking changes in next version of language, and you will have to wait couple of months, while this issue will be solved. Or just fix all the things yourself.
> after breaking changes in next version of language
In practice Rust doesn't make breaking changes anymore. (It hasn't since beta, and in a month or so 1.0 will be declared officially stable and it will become forbidden to make them.)
Various core Go team members seem to have a different philosophy regarding generics. They actually don't have a united front on this.
It seems Russ Cox and Rob Pike are either anti-generics or in the you-dont-really-need-them camp, but Ian Thompson and Brad Fitzpatrick have seemed very open to the idea - what they can't, however, agree on, is exactly how to implement them so that they make sense in Go. That's it.
If you or anyone out there manages to produce a proposal of how they should work/look like and even a fork of Go implementing the idea, it will be taken seriously, at least by some core Go members.
I have a feeling that generics are coming. And I have a feeling they'll be very Go-like - an external tool with code generation, not special syntax. Just my 2 cents.
I think adding generics to a stable language is actually a hard thing to do. There's more than "that's it". Rust has had many major and minor changes regarding generics solely, which has broken backward compatibility each time.
The Go team may find a brilliant way to accomplish this, but I think the only viable way left is, as you said, using code generation. Either C++-way, which is a special syntax but still a form of code generation, or an external tool. But neither of them is elegant, because you cannot fully utilize the convenience that the type system give. These might be the concerns that the Go team has.
Maybe the "elegance" is a factor as well, but I haven't seen it mentioned. All I've seen mentioned is: a) can't change syntax b) can't take huge performance hits at run time or at compile time c) can't break backwards compatibility d) talk is cheap - provide a working implementation
So far, nobody has been able to show all 4 of these requirements, so nothing has been done.
But when/if someone does, I expect it to be taken very seriously.
Almost. So close. But no cigar.
Go generate is for the package creator, not the package consumer. So you, as a package creator, may create a "generic" red-black tree, but unless you pre-generate all my use cases for all my data types, I can't pull your package and then use go generate to create Tree<int> and Tree<string> if that makes sense.
That comment was there because my point was not about generics, but about programming language features (that are must have, the must have list of course being different for everyone) in general.
> Agreed. Go lacks many things, but the "zen" of Go is wonderful feature most people aren't aware of, or under appreciate.
It's funny that you use the word "Zen" - about two years ago, I gave a talk about Go to the New York Python Meetup about why I switched to Go[0], and the punchline was that Go fits the Zen of Python[1] better than Python does[2].
[0] Before anyone gets upset - they asked me to speak, and they were genuinely happy with the presentation. It's not like I went in there to troll with a talk on "This is why your language sucks"!
But I can tell you in my experience that this type of forceful "everything is a error, no warnings" and "it is done this way (formatting for instance)" are a breath of fresh air. Having dealt with team members that barely know how to program and think a compiler spitting out an executable means it's ready (what warnings? why do those matter, it compiled), Go makes coordinating with them a lot easier. It forces them to be more correct before an executable is created. It doesn't make them better, but at least the rest of the team can work with what they create until they do get better.
Also, the simplicity of the language sure helps everybody (regardless of skill) get up to speed quickly. People that know what they're doing may hate there isn't some special feature they love (generics, etc) in the language, but working with a team of varied skill is so much easier this way.
In before "but adding generics does not make team projects harder, look at language ..."