An Introduction to Golang by Google

01 Apr 2016

In 2007 Robert Griesemer, Rob Pike, and Ken Thompson created a compiled and statically typed language called “Go.” This new language was meant to resolve problems they regularly experienced with languages they were using at Google. Here is a list of the pain points this group sought to address:

  • Slow builds
  • Uncontrolled dependencies
  • Different subsets of the language used by programmers to solve the same problem
  • Hard to read and/or poorly documented code
  • Duplication of effort
  • High update costs
  • Version skew
  • Difficulties in writing automatic tools
  • Cross-language builds

Once these issues had been compiled, the engineers set the following parameters regarding the creation of a new language:

  • It must work at scale:  Golang developers must be able to scale programs as needed.
  • It must be familiar:  Go creators did not want Golang developers at Google to spend too much time learning the language.  As most developers at Google are familiar with C family languages, the group determined the new language should resemble C.
  • It must be cutting edge:  Languages widely used today were created before the invention of multi-core processors and the establishment of web development as a specialized field.

The result of these efforts is a language that surpasses all expectations. Go does not have classes, for example. Inheritance and exceptions have been eliminated. Instead of inheritance, Go values composition. Although most languages have inheritance, Go creators believe it is overused and needlessly complex. They have created a simpler method to tackle the same problems.

In contrast to type hierarchy, Go has interfaces made up of collections of method signatures. Interfaces are implemented by objects implicitly, meaning an object implements an interface just by implementing its methods. There is no need to explicitly specify the interface. Such design leads to a composition of types instead of type hierarchy. Although this process may be a bit confusing for developers at first, it will eventually allow them to create more flexible code.

Concurrency has become widely discussed in recent years as machines gain more and more cores in their processors. Executing concurrent programs on multiple core systems allows the use of all cores without changing the code. Nevertheless, there is also a benefit when running a concurrent program on a single core machine – threads do not need to wait for another thread that is blocked with some IO operation. Go gives you the advantage of writing concurrent code without spending much time on it. A way to execute some function concurrently is just specifying go in front of it:

go f(x, y, z)

With Go, users don’t need to worry whether a machine that executes this code has 1 core or 10, or whether other threads are blocking CPU or not. Go manages the entire process. When you specify go before the function, Go executes the command in a so-called “Goroutine.” Similar to threads, but much more lightweight, Goroutines are multiplexed onto OS threads. You can start thousands of them, even hundreds of thousands, and Go will load the CPU as much as it can. Channels exist in order to communicate between Goroutines. These channels contain directions and can be used to synchronize execution between Goroutines. In addition, a select statement allows waiting for particular messages on multiple channels:

select {
case message1 := <-channel1:
    fmt.Println("received", message1)
case message2 := <-channel2:
    fmt.Println("received", message2)
}

Despite all these significant benefits, Go has experienced some criticism regarding exceptions. Instead of exceptions, Go has errors. This is not just a different name for exceptions. Errors are values and are returned as a separate value from a function. Functions in Go can have multiple return values:

file, error := os.Open(fileName)
if error != nil {
    return error
}

In contrast to catching exceptions, Go users need to check if each individual error value is empty. Some developers are not happy with this requirement, while others believe it makes the code clearer. Go creators justify this function by saying that there is nothing exceptional about most errors. Simple if and return works well for them. For example, attempting to open a file that does not exist is a common situation; there is no need to have special language constructs for that.

Of course, unexpected, unpredictable situations occur while running the code. In order to stop execution immediately, ‘panic’ functions are in place.  These are kind of like exceptions but are not a recommended way for dealing with errors. A panic is a built-in function that can take a string parameter: panic('message').

Go has become popular in recent years and is used in many large projects. No doubt, Google is the main user as it was built in response to their specific needs. They actively maintain the language, but most of their projects are not public. The biggest open source project is Docker, which has a number of repositories on Github. All in all, Go is very unique. Golang consultants may feel this language takes a bit of time to get used to, but its benefits are worth the effort.