Thoughts on Go after a few days
bklimt.tumblr.com
bklimt.tumblr.com
Great! But it might have been more productive to hold off on the blog post until you've been using it for a few weeks, at least. You make a few barbed comments about the language designers, but you are nowhere near familiar enough with Go to be justified in doing so (IMO).
> If Foo is derived from a struct, and it doesn’t work when zero-valued, then there should be a function somewhere called something like NewFoo. Good luck finding the right one.
I've never needed luck, here. This isn't a real problem for actual Go programmers.
> Why is there this special function that construct these three random types?
They're not "random types". They're special built in types that are managed by the language runtime. That makes them distinct from anything you can write as a user, and that's why they use the built in make function for initialization.
> I think channels are value types, which is strange since it’s the only other type created with make.
No, channels are reference types, too. Just like everything created with make.
There are more misconceptions and inaccuracies.
Haha, I agree. I wrote it mostly to try to get my thoughts straight, and didn't expect it to be posted to Hacker News. :)
But my criticisms are that these things make Go hard to learn. It may be a great language once you get everything straight.
> No, channels are reference types, too.
Ah, good to know. That wasn't clear to me from my first reading of the docs, but you're definitely right.
Might be a good idea to continue honing that post. It is already useful and could be much more so.
This article written by Rob Pike covers the reasoning behind many design decisions: http://talks.golang.org/2012/splash.article
You seem determined to be dismissive here, which is unfortunate because there are few others on HN who are qualified to address these criticisms.
But even aside from that, it's valuable to have someone's early impressions of a language. They may change later. That's cool. But it's also cool to know what they think early on, because it's fairly likely other people will have the same experience. Whether or not his comments represent misconceptions and inaccuracies, they still report his experience. Other people can benefit from knowing others shared the same experience, and if he blogs later when he has more knowledge they can also see how his experience changes over time.
I encourage more blogging of this sort.
I totally agree, but he makes a number of conclusions (or at least strong statements) throughout that, to me, seem premature.
For example, in the introduction: "I get the feeling that Go was designed by System Engineers, who focus on implementation." Systems engineers focus on APIs as much, if not more so, than other programmers. Systems engineers build the things at the bottom of the stack, where API design decisions have a fundamental effect on everything built above them.
It's definitely worth reading this: http://talks.golang.org/2012/splash.article
I mean, I get it, lots of people give Go a hard time, and it must be wearying to see the same arguments dished out again and again (no GC complaint this time, nice right?).
...but surely, when someone makes a post like this that address actual issues they see with the consistency of the language, which aren't the same as the usual run of the mill complaints about GC, generics, etc. a more mature response would be:
Hm, that's interesting. I guess I can see why some
people might think that's a language inconsistency or
issue, but maybe you'll appreciate the Really Smart
Reasons we've chosen to do that when you're more
familiar with Go.
Instead of: STFU. You don't know what you're talking about.
Is it really that difficult to just be a little bit more humble, and consider that other people may have a valid point or two to make?This is a complete mischaracterization of what I wrote. I wasn't being antagonistic. At least, it wasn't taken that way by the author of the article: http://news.ycombinator.com/item?id=4930618
It's definitely a little ironic that what is needed to make a regular grammar makes the language more inconsistent.
E.g., instead of a special ":=" declare-with-auto-type+assign operator, just use ":" in all type declarations, and make the type optional in initialized declarations. Then the following would all be equivalent:
var x : int; x = 5
var x : int = 5
var x := 5
Using ":" in declarations would also make them more readable, and more consistent with most other languages using this type of declaration syntax. [If you've read my other comments about Go on HN, this is a pet peeve of mine... :]Go's syntax does feel pretty sloppy, like it evolved under a variety of different authors and directions, and never really got a cleanup pass in the end...
The difference between make and new is well covered in documentation and on the mailing list.
Do I literally need to link you to the FAQ entry for "make vs new"? Or the docs for initialization? You're the one spreading FUD.
FYI, the grammar is context-free, not regular.
foo := map[string]string {}
bar := []string {}
That said, like all good languages, it's perfect until you run into the small list of warts that enrage you. In particular, as the author said, the fact that the make() types are different can get pretty annoying. What's really going on there are that make is really the only generic function in Go. That's why it's special -- unlike a lot of Go builtins, it's impossible to write make() in Go. I really do think this is the biggest single wart in the language (although there are others).
I don't really agree with the author's complaints about declaration syntax. I don't find it distracting: just figure out an idiomatic way to do things and move on.
Not having nil-able strings is annoying though. There are plenty of functions both in the standard library and in my own code that return ("", error) simply because the first return type is a string -- in a similar function with a different return type, I'd just return (nil, error) and be done. Not a big deal but it is a wart.
There are also some definite problems with the standard library, but I expect these will get fixed by OSS packages in time.
Before we all dump on Go though, it's worth pointing out some of the really cool innovations in the language that work great:
* Dependency management in the code is awesome. I love that importing a package and not using it is a compilation error. This seems to be so successful that they went and made declaring unused variables an error as well, which also does wonders for readability.
* Once you understand how you're supposed to use it, the GOPATH story is pretty great. Package management can get tricky and it's cool to see a language attacking it head on from the beginning -- you don't want to end up like Ruby.
* The notion of a Go "package" for namespacing -- and the exporting of CapitalizedVariables but not uncapitalizedVariables makes for very readable code. I really like it.
* The multiple return types for error handling definitely makes for more verbose code than the try-catch-finally pattern, but it also feels a bit cleaner. It takes a while to fully see the benefits of it, but it works great in the end.
I'm really excited for the future of this language. I think with a few more years, a few better frameworks, etc, we'll be able to do some really cool stuff very very easily in Go.
I must agree with your overall praise for the language. The package/export system and the official tooling is masterfully done!
In comparison to other languages out there, like Objective-C and C++, this sounds like an i-th world problem.
Though I felt the same way about Go, I may just be terrible at noticing things like this.
i as in i^2 = -1.
> I feel like Objective-C is very easy to pick up and consistent
I like Objective-C. It's quite wordy, however. The libraries are what's hard to pick up. That, and things like having to copy blocks before you send them off places.
Foo foo_module_new() ?
I don't know Go, but I would do that in C for example and just create an opaque struct for example.I've never really done any Go, but aren't these just different use cases for a Slice? Why would they need their own data type?
Pushing onto a stack is equivalent to `s = append(s, obj)`. Checking if the stack is empty is equivalent to `len(s) == 0`. Peeking at the top (assuming its non-empty) is equivalent to `top := s[len(s)-1]`. Popping from the top (assuming its non-empty) is equivalent to `s = s[:len(s)-1]`
It's reasonable for someone to be confused about this; my rationale is that these three types are basically where go allows "magic": all of them support special syntaxes (the range operator, optional multi-value context when looking up a map, the select operator on channels), so they have a magic initialiser, ignoring Go's usual "declaration is initialisation" rule.
As others have said, it's not too bad a special case in the context of the language. The problem I have with it is that it introduces the possibility of run-time errors that in a language this advanced and generally so well-designed should probably be compiled-time errors: panics when you assign to keys in nil maps or deadlocks when you send to a channel you forgot to initialise are both errors of a class that the language generally doesn't have.
however, that doesn't necessarily mean that go is "a bad language". it's more a cultural thing, as far as i can see.
go has some nice ideas and is a big advance over, say c or c++. it's also made by people with a lot of experience and, for want of a better phrase "good taste".
but it does have a certain culture (or, if you like, a disregard for a certain culture).
nothing very useful seems to have come from these observations, and many people have made them. it's probably better to simply consider the language as a tool and work with it on its own terms. perhaps the most you can say is that, because it does choose its own path, you really do need to use it in the way intended by the authors.
Why can't you add methods to types outside of your package boundaries? Because Go aims for clean, comprehensible, robust boundaries between components: http://talks.golang.org/2012/splash.article
That's interesting. Go is one of only two languages that I've been able to learn by writing production code without feeling like I'm getting "held back" by my inexperience (or, on the flip side, holding others back). It never felt like a chore to me; there was only one "gotcha" that caused me a significant amount of frustration.
> So what’s the response from Go’s designers about the requests for nullable strings? To treat the empty string as a special value. Sometimes it’s like they haven’t even read their own design justifications.
The only time I've run across this is with JSON encoding/decoding, but there's a really easy solution to this (take a look at gobson, for example[1])
Reading this I see a lot of the reasons I like Ruby: no worrying about different constructors or needing to worry excessively about types. If only Ruby treated everything, even the little bit that is syntax, as mutable objects, it would be near-perfect (and it would basically be Lisp). But, it's close enough.
Maybe if Go could become Ruby...
And there may be a variety of ways of doing things, but that's because (1) Ruby has been more well-used than Go, and (2) it has more flexible loops, etc. to make it less verbose, and yes there are a variety of ways to add methods, attributes, etc. but after you spend a little time to understand how the Ruby object model works, you'll understand why- almost everything is an object. Also, the language has evolved, so there are some differences in syntax between 1.8 and 1.9 but you can still use 1.8 syntax in 1.9.
Go code is nothing if not explicit.
For a company, it makes sense to check your GOPATH into your own source control system, so everyone has the same version of the open source libraries you're using. Then upgrading some open source libraries to a new version is a commit like any other change.
I haven't messed with Go, but nothing about the idea of defining a path for source modules sounds braindead on its face to me. I certainly would give the benefit of any doubt to the designers of Go over some random troll.
How is that different than the /I ${INCLUDE} path of C/C++ compilers (and many other languages)?
This screencast might help: http://www.youtube.com/watch?v=XCsL89YtqCs
As it is stated in the screencast, a programmer needs to add the workspace to $GOPATH to be able to build the source. That means that for each project being developed in Go, you need to add the path to that project to $GOPATH to be able to build it.
That is a very poor way to do develop software.
Personally, I keep 2; one for external packages, and one for ones I'm working on.
What you meant to say was, their braindead idea was that if you want to be able to trivially use ANY go program or library on GitHub, you can use $GOPATH and the go tool [1] and not fuck around with autotools and makefiles.
If you're into S&M, no one is stopping you from using the core pieces of the `go` tool by hand.
[1]: ALL of my code can be download, built and run with: `go get github.com/myname/myproject; myproject` (I have $GOPATH/bin on my path)
Referring to gc makes as much sense as referring to gccgo.
If you want to do your own thing, you're free to ignore the rest of the community in this respect, and create your own build mechanism. In fact, if you pass the "-x" flag to the go tool, you can even see how its accomplishing what its accomplishing; which might help you write this better build tool.