Go is a modern, procedural, concurrency oriented language. It is started by Rob Pike and Ken Thompson et al. The language is defined to be a “general-purpose systems programming language”. I have played with Go for a short while, and have some opinions about it. I’ll discuss these ideas in this blog post.
Go has good sides to it more than bad. Using a small syntax, it remembers of C at the first glance. Go is a procedural language, just like C is. But in contrast to C, one has ability to use function literals, which can be useful at times. Go is a concurrency-oriented language, which is a popular marketing buzzword for newborn languages nowadays. In contrast to most concurrent languages, Go is an imperative language. Offering the so-called goroutines, Go language brings a different way of writing concurrent programs.
Go creators are quite eager about reducing the compilation time. Rob Pike has criticized the dependency model of C/C++ in some keynotes. The language is very strict about dependency management. Imports are module based, in contrast to the C model of header files and file inclusion. This is, quite frankly, very nice. The module is the code and the code is the module. Management of name visibility has been undertaken nicely (ignoring the issue of imposed naming convention). There is no questions possible about visibility of a name throughout the package.
Go language design tries to reduce typing whenever possible. Type inference
is used nicely to prevent C++ style unnecessary syntax like Foo<Bar> foo =
new Foo<Bar>(baz);. Interfaces feels somewhat absurd in the beginning, but
very convenient in time. One does not need to explicitly declare that he
implements an interface; if the methods declared in interface is defined for
the data structure, it implements the interface.
Allocation of memory is handled nicely, although deviating from what a systems language remembers me of: Go is a garbage collected language which exposes no primitives of explicitly managing memory manually. This means it is inconvenient if not impossible to implement operating systems or drivers in Go. Being mainly targeted towards networked and concurrent systems, this is the right decision too.
Go offers very convenient syntactic sugar for arrays, array slicing and hashmaps. Also, the syntactic constructs for deferring jobs to the end of functions and creating small so called goroutines are nice. But, Go code looks hairy at the top of function declarations and control flow statements. Go has a for loop only, and you have to use it for any kind of iteration you want to do. It can become a traditional while loop or a Python style for-in-range loop, which is a bit cumbersome. If statements have initializers like for loops, which is cumbersome most of the time, even with short statements.
Goroutines and channels are main concepts of concurrency in Go. One can easily fire off a function inside a goroutine and use a channel to pass back data. Although the concept is cool, I did not really like it and feel natural with it.
Go is very, very, very, very, very strict about being thrifty. The compiler
is quite parsimonious about giving you imports and variables, and yells every
single fucking time an unused variable/import is encountered. Don’t comment
out an expression to just see if it works, it possibly won’t compile even if
the function is valid. fmt is the package containing the Print* stuff,
and if you use them to debug, be careful about commenting them out! You will
have to go to the top of your file more often than you’d ever before. And
this is not even a warning, it is a compile error! A very silly, inconvenient
and, and basically an annoying feature. If the compiler knows that it is
not used, it may just throw it away, discard it and not give it a fuck. The
syntax/import tree can be shaked. And this will not create a performance
penalty too; you anyway check it to see if it is used. It is not an error to
declare a variable and not use it (or put it there to come back later). It is
not an error to temporarily comment out some flipping printf. This bit me a
lot :)
Go syntax, too, is very strict. The compiler imposes a very strict syntax. A
very unreadable syntax, mainly for the control flow and function headers. You
don’t have a chance to put braces to the newline, because Go people apparently
wanted to keep all the parens for the function headers. You need braces even
for a one-liner if/for statement. A one-liner void function with a single
if statement involves at least 4 braces. But you are lucky to save a couple
of parens from your if. If your function has a receiver and returns a
tuple, it involves at least 3 couples of parens. if has an initializer,
which is totally illogical. Go guys tries to impose a clear and succinct
syntax with the expense of a clear and succinct syntax.
Go also does not have generics, but I did not use Go so much to see if this is a problem or a gain. I don’t believe authors of languages like Haskell, Scala, C++, Java et al. are wrong about the importance of this concept. And, Go neither offers any kind of overloading, so, the only way to not duplicate code is to use interfaces.
There is two major compilers for Go: 6g et al series of compiles, directly from the core team and gccgo which is a GCC frontend. Both are in C. Go is not a self contained language, which, in case of a natively-compiled statically and strongly typed language is a lack in my opinion.
In conclusion, I did not like Go. It’s syntax is stricter than Python with no apparent reason and even adulterates their points of clear code sometimes.
Thanks for dallying away here! I wish you enjoyed your read. And, I definitely suggest you to take a tour of Go to see how you like it. Even if you don’t like it, a new language is a new romance for the hacker. Have a nice day!