My thoughts on Go

Summary

My initial knee-jerk reaction about Go was correct: it's a language made by someone who is clearly very opinionated and seems to miss the forest for the trees. However, it seems that their opinions align with mine enough that I somewhat enjoy using it. I  can certainly appreciate the simplicity of it.

Positives

Testing

I like the way Go implements tests. They're simple enough, have reasonable conventions, and are built right in. However, I would have traded this for more valuable things like a better standard library, real classes, or generics (which finally came in 1.18).

Simplicity

I can definitely see how Go would make it relatively simple to kick out a quick project, and also give you a scalable foundation. Once you have your favorite set of libraries you would probably forget all the things the language itself lacks. Cross-platform support is also good, so it's a solid language to have in your tool belt.

I am including performance within this simplicity category. With C# becoming more cross-platform, and performance similar to GO (depending on the workload), it would really be a toss-up about which language is better to use. Even though Go folks may say Go is faster than C# benchmarks show it's not always the case; and when it is, it's not a landslide.

When I compare how much it takes to start and deploy a C# project, I think the process in Go is easier.

Neutrals?

Semicolons

This is one of the things that made me uninstall Go after about 10 minutes the first time I tried it. I really like my programming languages to be structured. I don't believe white-space counts as structure; I have a hard time respecting languages that use white-space instead of symbols for grouping code.

I want this structure so that I can spend more time writing, less time trying to understand as I read, and know that the compiler will yell loudly when something is wrong.

Go's strong-arm approach manages to save us from typing semicolons (they are still generated in the background) by disallowing code to be written that would be ambiguous without the semicolons.

Once I realized this, I was able to able to begrudgingly stop typing semicolons.

Negatives

Standard Library

I would much rather have a more robust set of standard functions and types than built-in testing. I think it's an absolutely inexcusable joke that Go doesn't come with basic collections like Set, or support basic collection functions like removing an item from a slice. Yes, this is ME being opinionated.

I completely understand that the purpose of Go is to be efficient, so there's a strong aversion to having inefficient functions - like removing an item from a slice. Obviously, the best approach is to not do that, but that isn't always possible. It seems like the hope is that if these functions aren't available then people won't do those things.

The fact is these functions are needed sometimes. Their absence means that instead of people being diligent about when to use or not use them, they have to spend their time writing the functions when the time comes that they are needed. Not only is this wasted time, the average person's code is likely to be less efficient and have more bugs than a well tested part of the standard library.

With that complaint out there, I will say that Go does a better job of including more "in the box" with standard libraries than JavaScript does. But there's still just too many things that feel like a missing step on a stair case.

Classes

This meme most accurately describes how I feel about Go's "lack of classes"

not sure if serious
not sure if serious

I can't tell if they're really serious when they say they don't have classes, or if they also say it as a joke to themselves.

Go insists it doesn't have classes, but instead it has Structs (the data), and you can add methods (or functions with receivers) to give them functionality. You can also make constructors, and the docs suggest you name them consistently like New...().

I don't know about you, but that sounds a lot like classes to me. Except instead of the language enforcing a standard of how a constructor looks, or member functions, you have to tape them together yourself. I really don't understand why Go, as opinionated as it is, does not enforce standard constructors.

My only guess about why things are this way is that they decided in the beginning they "would not have classes", so they keep taping things on that look and smell like classes, but are not classes.

TL;DR: Go has classes, it just makes you write them in a very stupid way. 

Generics

As of 1.18, Go finally implemented Generics. I haven't gotten to play with them yet, since the containers Fabric uses are stuck at 1.17, so I can't say how good or bad the implementation is.

What I can say is that pre 1.18, the solution is a special type-based switch that lets you take an interface or anonymous object and check it against a specific type, and then for the duration of that switch treat it as that type. The "gotcha" here is that your function return is still unaware of the actual type, so you either have to return an interface or an anonymous object.

switch t := dto.(type) {
  case typeA:
    t.typeAProperty = value
  case chainTypes.DepositMoneyDto:
    t.typeBProperty = value
  ...
  default:
    panic(fmt.Sprintf("Cannot handle unimplemented type: %T", t))
}

This just infuriates me. Go can understand that a struct implements an interface. Go can handle making a switch based on this. But for so long, Go refused to implement real generics. I don't want to know the amount of duplication has happened to support the same function for multiple types by developers using Go.

Final Thoughts (complaints)

As I mentioned above, Go feels like it gets stuck in idealism. Sometimes, its approach to making things "faster" is forcing all developers to do things the way one guy believes is best. Yes, the whole world would be simpler if we could just force everyone to do things one way - but that's not necessarily a valid way to make things "better".

The other thing I've seen in a few ticket / bug responses is essentially: "This isn't in scope for Go. We only care about the 90% use case." Aside from being unfriendly and rigid, this is also not a very thoughtful argument. If you have a tool that is lacking 10% in everything you use it for, you will always be annoyed when using the tool.

The thing that makes these two things especially annoying is the inconsistency. Certain things (like testing) were deemed important enough to be included in the base language, other things (like slice modifying functions and generics) were not. All of this seems based on someone's opinion of the "best" way to do things; it seems improvements that make the language more generally usable are hard-won and slow to come.

I really need to hang out with some people who speak Go as their native language so they can show me where I'm missing some easy ways to do things, and obviously wrong about other things!

Comments