« Back to home

My Experience Learning Go - Pros and Cons

Posted on

For the past couple days I’ve been going through my code katas using the language Go. Thus far, I’ve done the same process using Ruby and using Python.

Go is a very interesting language. There are a lot of aspects that I really like, and some that I don’t like so much.

Pros:

  1. Clean syntax - Go feels cleaner than Ruby and a little cleaner than Python.
  2. Static and native compilation - Go statically compiles to a native binary. This means your program is compiled to one binary with no dependencies - no JVM, no framework required to install, just one native binary.
  3. Typed and compiled language - I still have a slight preference for compiled languages. I have certainly gained an appreciation for interpreted languages while learning Ruby and Python, but I still prefer compiled languages, especially for complex problems.
  4. Defined style rules - Go has defined style rules and built in tools to format your code. This was just a little annoying at the beginning, but I do appreciate it now. I’ve worked on teams that have changed style rules along the way - while not a huge deal, I can appreciate having the coding style defined so there is simply no discussion on the issue.
  5. Strict compiler - The compiler is strict. For example, if you import a library and don’t use it, that is a compiler error. Similarly, if you declare a variable and do not use it, that is a compiler error. This can be annoying at times (see con below), however I found it helpful.
  6. Built in Testing - While not perfect (see con below) having the testing framework built in is great.
  7. Multiple return values - I did not expect to like multiple return values, but I found it quite useful and I think it is helped by the strictness of the compiler.
  8. Excellent parallelism - The built in parallelism is excellent. That includes go routines and channels. I didn’t use it too much with my simple tests but I really like the implementation.
  9. Simple declaration - Type inferred variable declaration with the := statement is perfect.
  10. Typed duck typing - There is no way to declare something is implementing an interface, you just implement the required methods. Someone else described it as “type-safe duck typing”, which I think describes it well. It sounded a little dangerous when I first read about it, but in practice everything is well checked by the compiler so it is not an issue.

Cons:

  1. Array/Slice confusion - Go is built around arrays and slices. They are way too similar in syntax and way too different in behavior. When learning Go, it took me a long time to realize the differences and how important they are to know.
  2. Slice API disappointing - Go slices (dynamic arrays with extra implications) are a bit disappointing, especially appending to a slice. To append to a slice, you have to do this mySlice = append(mySlice, value) I think this is part of the implementation leaking through. Something more like mySlice.Append(value) would be much cleaner. For such a basic part of the language, it is a bit clumsy.
  3. Lack of generics - I think part of the problem with the slice interface is the lack of generics. If you had a generic list, the interface could be pretty clean. There is a linked list implementation, but because of the lack of generics, it is essentially untyped.
  4. Lack of list operations / comprehensions - I think mostly because of the lack of generics, there is a lack of useful list functionality. For example, if you want to find the maximum value in a slice or array of values, you have to loop through the values manually. This just seems silly to me. It should be one line of code. There are probably libraries that provide this, but this stuff should be built into the base language.
  5. Lack of method overloading - because there is no method overloading, the API explodes a bit. There are 8 integer types (signed and unsigned), so if you had a Max method, you would have to have 8 different method names to handle just the integer types.
  6. Not really object oriented - The OO aspects of Go seem to be tacked on rather than abstracted away by the language. It is a similar approach to having the first argument as “self” in python. Something like inheritance can be achieved using composition. I think it is a bit of a stretch to call Go an object oriented language.
  7. Compiler gets in the way - The compiler strictness does get a little in the way when commenting out code temporarily. For example, if you want to test something and you comment out the only code that was using a library, then that library import becomes a compiler error.
  8. Incomplete testing framework - the testing framework lacks some very basic functionality, specifically around checking expected values. This means you have to write if statements to check values and then log errors. That means you have 3 lines of code (counting brackets) to check a variable value. That is just silly. So instead of test.AssertEqual(1, len(nameList)) You have to write:

    if len(nameList) == 1 {
      test.Error(...)
    }
    

    (That is supposed to be 3 lines of code, but I haven’t figured out the markdown yet.) This is not a huge deal but it does show the philosophy behind the language. I can appreciate having a minimal API to learn, but I would guess 99.9% of testing frameworks have some sort of one line assert method to check values. In this case I disagree with the minimalistic approach to the API.

  9. Heavy handed minimalism - Along the same lines as the lack of functionality in the unit testing framework, there are other aspects of the core API that are just lacking. For example, there is a Math.Min method for float64, but not for int or any other type. Sure it is a simple if statement, but decisions like this add up to make your code unnecessarily long and harder to read.

  10. Preference for error codes over exceptions - I’m a bit uncertain of this. The problems I’m doing aren’t quite complex enough to gain value from exception handling, but as a general rule Go programmers prefers returning error codes over exceptions. I agree this makes sense with things like a hashtable / map, my initial impression is that it is a little too heavy on the error code side.

  11. Types are defined in the opposite order of C/C# (var i int vs. int i). There is some discussion about the reasoning, and I’m not sure I agree with it. My guess was it was done just to be a little different than other C based languages. It doesn’t really matter that much in the end, but it is slightly annoying.

  12. Odd package management - For the most part, package management is quite good, but I had one problem: Adding libraries to your workspace involves source control of the package you are adding. This is very strange. So, for example, I started using a unit testing library that added asserts. To add it, I had to install the ‘bizarre’ source control management, because that is what the library authors use. That seems like a poor implementation to me. How many different SCM tools will I have to install just to use different library packages?

  13. Documentation is good, not great - This is a pretty minor gripe. The documentation is quite good, but it could use more examples.

Conclusion

While I have listed more cons than pros, do not read too much into that. I really like Go and I would use it in a project. Overall the language just feels a little young, especially missing generics and to some extent operator overloading.