I talked to a bunch of people about Go at the dotRB conference, and I’ve been experimenting a little. My main aim is to find a language that I can use for portable command line tools that isn’t C or POSIX shell, so I’ve not been looking at any of the concurrency or scalability benefits that are often talked about.
After a few tutorials, and an afternoon hacking on a command line tool, here’s what I think so far:
Good
Having a really strict compiler after working with languages like Ruby, Python and JavaScript for a long time is actually really nice. Go programs won’t run if they contain unused imports, unused variables, or type errors. It can make experimentation a little slower than it is in Ruby, but it catches a lot of my mistakes.
The type system is a lot more light weight than others I’ve used (C, Java). For example, if you declare a variable and assign to it at the same time the type of the variable is inferred from the value and you don’t have to explicitly declare it.
The standard library declares lots of little interfaces, which are really useful. For example there’s a Stringer interface which just declares a String method (like Ruby’s to_s, Python’s __str__, etc.), so if you only depend on an object’s String method you can accept a Stringer instead of a more specific type and get some of the benefits of duck-typing while keeping the strict type checking.
Bad
I’ve not found a good way of dealing with errors yet. A lot of the standard library functions return a result and an error object, and my code it littered with these kinds of error checks:
if err != nil {
panic(err)
}
There’s a distinction between methods on types and methods on pointers to types. I don’t understand what this is for, but it’s caused some confusing bugs where I’ve passed an instance instead of a pointer and suddenly nothing’s worked as expected. This might just be confusing because I’m a Go beginner though.
Is anyone else playing around with Go? I’d be curious to know what you think.
Yeah I’ve been playing with it. To your questions about methods on types vs pointers, here’s an article that touches on this subject. To me, I think one should stick with pointers unless you have something very special.
I’ve not found a good way of dealing with errors yet. A lot of the standard library functions return a result and an error object, and my code it littered with these kinds of error checks:
if err != nil {
panic(err)
}
Go code will have if err != nil spread throughout it.
It’s idiomatic Go and is an intentional design decision to encourage us to explicitly check for errors where they occur (as distinct from the convention in other languages of throwing exceptions and sometimes catching them).
Despite looking verbose, it’s really easy to read. Go’s approach makes it easy to see which functions return errors and to handle them using the same language constructs employed for any other, non-error tasks.
It looks strange at first but I’ve grown to really appreciate the language’s design decision.
All interfaces values are just two pointers - one pointer to information about the interface type, and one pointer to the data from the value you passed into the interface …
… interface values are very small - just two pointers. When you assign a value to an interface, that value gets copied once, into the interface, but after that, it’s held in a pointer, so it doesn’t get copied again if you pass the interface around…
… Interfaces are types, just like string is a type or Camel is a type. They aren’t aliases, they’re not magic hand-waving, they’re real types and real values which are distinct from the type and value that gets assigned to them.
There’s a distinction between methods on types and methods on pointers to types. I don’t understand what this is for, but it’s caused some confusing bugs where I’ve passed an instance instead of a pointer and suddenly nothing’s worked as expected.