POSTS
Getting Started with Go
Go is a statically typed system language designed for high productivity and efficiency. I’ve been reading about Go on and off for a while, but not been able to play around with it much until recently. Coming from a Java background, here are some things that I found remarkable or unusual from my beginner’s perspective.
Opinionated
Go’s guiding principles are to be simple, easy to use, fast, and efficient. This means removing syntax debates with the go fmt tool, having a picky compiler which disallows things like unused variables or packages, and disallowing inheritance in favour of composition. This definitely contributes to the learning curve for a beginner who tends to write sloppy code, but with the fast compilation speed of Go we can get feedback on mistakes pretty quickly.
Interfaces
In Go, the type hierarchy is flat - there are no extends
or implements
keywords to establish relationships between types. Instead, Go derives their relationship automatically - any type in Go that contains all the methods of an interface is treated as having implemented that interface already. I didn’t fully understand this until trying to do the simple task of opening a JSON file from the filesystem and parsing it. json.NewDecoder takes in an io.Reader interface. Meanwhile, os.Open returns me a File type. Being a Java programmer, naturally I looked around for some way to wrap a “Reader” object around the File type so that I could satisfy json.NewDecoder, similar to how FileReader works in Java. After some fruitless searching, I finally realised that File already implements the io.Reader interface since it has a Read function, meaning that I could pass it directly to json.NewDecoder.
Go’s interfaces allow much more flexibility. For instance, you could create new interfaces that core types already satisfy. Interfaces also eliminate boilerplate such as Adapter classes. However, this also makes it a bit harder to discover useful relationships. In Java, the API docs for the Readable interface clearly shows us which classes implement the interface, whereas in the Go documentation I have to fit them together in my mind like puzzle pieces. This is probably a surmountable problem though, since the Go compiler clearly knows where all the relationships are and this information could be extracted by some tooling.
Go Workspaces
With other languages like Python, Java, and even C++, I’m used to being able to put my code anywhere I want, and it’s quite common for me to end up littering various folders with one-off scripts and programs. However, Go strongly encourages the use of a single global workspace, where all your code and third-party dependencies are placed. Out of the box, Go also doesn’t come with any package dependency management solution similar to Maven, and recommends either relying on package authors to maintain backwards compatibility when new versions of a library are released, or to make a local copy of the library. Fortunately, it seems there are tools like godep that allow you to capture dependency versions instead of worrying about backwards compatibility.
Error Handling
The style of error handling in Go is taken straight from C - all functions that can result in an error simply return an error value instead of throwing an exception. It really is just an improved version of C error handling, with less verbosity and more context. The more conventional style of exception handling with try/catch is definitely cleaner-looking, but the Go designers argue that this creates more complex flows of logic.
C-style error handling will take me some getting used to. I have to confess, for now I’m just using “_” placeholders to ignore error codes or calling panic() to abort the program.
-
golang