Why you should try out Golang
Golang offers some refreshing aspects compared to older languages, let’s explore a bit of that.
The programming langage Golang, or Go, was first developed by Googlers in 2009, and is since being regularly updated to make sure it doesn’t lack the most important features. But let’s focus on the new, before exploring what it still needs to copy from other languages.
Concurrency becomes a pleasure (almost)
Concurrency in Go (meaning having multiple threads running different operations at the same time) is made very easy thanks to a great feature of the langage, called goroutines. Simply adding the keywork go in front of a function call makes it concurrent, and your code continues executing without waiting for the function to end.
go func() {
fmt.Print(1)
}()
fmt.Print(2)
The upper code may print either “1 2” or “2 1”, according to the speed of the two threads (it will most likely print “2 1” since the goroutine will need a small time to start).
With that, we can start building stronger and more complex distributed and concurrent systems with multiple nodes sharing information between them. To manage the unknown of the concurrency world, Go also make use of channels. They allow goroutines to synchronize, as a replacement of locks.
channel := make(chan int)
go func() {
i:=<-channel
fmt.Print("After ", i)
}()
fmt.Print("Before ")
channel <- 42
This time, we know with certainty that the output will be “Before After 42”, because the channel in the goroutine blocks until it receives a value, which is sent only by the main thread after having written “Before”.
The error management
Although it isn’t appreciated by everyone, I personally think it does the job well without being obnoxious. Here is the thing: Go works with errors like variables. There is no Exception as we can find in Java, Go wants the user to use and return errors and check for their nullness (nil in Go) when needed.
result, err := operationWithPossibleError()
if err != nil {
fmt.Println("We have an error here")
return error
}
Here when using the operation function, it can possibly return an error if something wrong happened. We receive it as a value and check it right after with this infamous “if err != nil”. Infamous for being used repeatedly in every Go program. However, it permits to keep track of the error easily and simply feels like a try/catch combination.
What about performances ?
Go being compiled to an executable file, it will be faster than for example Python execution. Compared to Java, Go won’t be able to work on a lot of platform without the help of the JVM, but it will be faster because it doesn’t need to load one at first.
For the same for loop of 10000000 iterations (1), making a GET request to “www.google.com” (2), or implementing 1000 threads incrementing a counter value and waiting for this value to be 1000 (3), we can observe below the time needed by each languages, in milliseconds.
Note that Python’s for loop is notoriously slow and Jython or Cython would beat that time. In addition, Numpy’s methods should be used when possible to make loop operations over arrays way faster.
Those examples are not comprehensive but still showcase some strong sides of the language.
And more !
- Go forces the user to write better code, by not allowing to declare an unused variable. According to the Go team, “the presence of an unused variable may indicate a bug”.
- Go is strongly typed and dynamically typed, meaning it allows creating variables without specifying its type, with the := statement.
- Go offers the defer statement to copy the idea if Java’s finally. It helps to make sure code is cleaned up at the end of the function in which it is used.
- Talking of cleaning up, Go also has a garbage collector, which doesn’t let you control what happens in the memory but makes the language easier to use.
- Go 1.18 will include generics, adding optional type parameter to type and function declarations
- Go contains a great test framework with everything needed, and the version 1.18 will also include an implementation of fuzzing.
Fuzzing is a type of test automatically modifying inputs to search for bugs in a program. It is used to find possible vulnerabilities in the program and thus fuzzing in parallel to the tests allows to prevent them.
- Go allows developers to fairly simply post the libraries they coded on GitHub to make them public and available. Anyone can import a public library in their program which makes the distribution easy.
- Some commands are usable by the developer to manage the project, such as go get to download the libraries to import, go build that builds the project to an executable, go fmt (possibly ran at every save) to format the code in a conventional way to enhance its readability, and so on.
About the downsides
As we have seen, some missing features are being added versions after versions so the language becomes more and more mature.
However, we can for example talk about the two different ways of declaring a variable, := and var. They slightly differ, since var allows to only declare a variable without initializing it, while := can be used with a mix of new and already declared variables.
Interface implementation feels weird in my opinion, because it doesn’t need to be explicitly written. If a type defines every types defined in an interface, then it implements the latter.
Go will make you familiar with race conditions, a type of error happening when the same data is reached by different goroutines.
array := make([]int, 0)
go func() {
array = append(array, 1)
}()
go func() {
array = append(array, 2)
}()
For example, running tests on the above piece of code with the flag -race will detect possible race conditions because access to maps or arrays should not be done concurrently, and you quickly will feel the need to create your own types of data structures with thread-safe functions.
As we have seen earlier, the error handling is pretty special, and its repetitiveness will be either loved or hated by the user.
When writing Go code, you have to be careful on the capitalization, since it indicates if the function is usable by other packages (or other go files). For example, when reusing Java’s terms, the function print() is private while Print() is public. You can observe that every function you call from imported packages are capitalized.
Go allows the usage of pointers, which can be at the same time very useful and confusing in the beginning.
Finally, the fact that every object has a zero-value leads to possible structs instantiated with none of the fields being defined, while the struct itself is not nil.
Is Go popular ?
According to the TIOBE ranking, Golang is placed in March 2022 at the 13th place of the most popular languages. We can see Go has had better days, and the community behind the language is clearly smaller than those of Python, C or Java, respectively top 1,2 and 3 with a rating superior than 10%. However, it is famous enough to have already tons of libraries ready to use and questions about common problems answered over the internet.
Final words
In the end, every languages have their pros and cons, so does Golang. It doesn’t have the libraries that Python offers for Machine Learning for example, nor the community and wisdom of Java, but Go definitely can be of great use when developing micro-services and distributed systems.
Thanks for reading !
I hope you enjoyed discovering some characteristics of Golang, if you have any question and/or suggestion let me know in the comments.