Go is built for grug brained programmers like me.
grug brain developer not so smart, but grug brain developer program many long year and learn some things although mostly still confused
apex predator of grug is complexity
complexity bad
say again:
complexity very bad
you say now:
complexity very, very bad
given choice between complexity or one on one against t-rex, grug take t-rex: at least grug see t-rex
The Go team took many years to add generics to the language. It was a good addition, and many argued that it was an obvious decision that should have been made sooner.
I disagree.
The simple truth is that when you’re building applications, especially back-end web applications or CLI apps (which is where Go shines as a language imo) you just don’t need generics all that often. They’re quite nice to have, but far from necessary.
Are you building a clever library using general-purpose data structures? Sure, generics make your life much easier. But let’s be real, I’m over here parsing JSON and shoveling strings into databases. I don’t need 3 layers of abstraction to get ’er done.
Smol-brain code work gud for application layer.
What else is Go good for? ๐
Before I start shitting on my favorite language, let me point out some of the other reasons I love Go.
- Grug-brained syntax (already mentioned)
- Statically compiled binaries
- A toolchain with built-in formatting, testing and dependency management
- Dependency management built on Git repos (no npmjs.com or crates.io)
- A standard library that cares about the web
- Goroutines and channels (concurrency that doesn’t suck)
- Fast despite a garbage collector
What would I change about Go? ๐
Not a hard question. It’s sum types! (Or enums, tagged unions, or whatever you want to call them).
Go currently has a shitty excuse for enums:
type Color int
const (
Red Color = iota
Green
Blue
)
They’re pretty bad. Go’s “enums” are verbose, error-prone, and don’t ackshually enforce much of anything from a typing perspective. Let me show you what I mean.
It’s just an alias ๐
type Color int
This is a type alias. At the end of the day, the new Color
type is just an int
. It’s not really a new type, it’s just a new name for an existing type. In this world, every integer on God’s green Earth is a valid color.
That’s crap.
If I wanted that I would just use an int
.
I want to restrict the set of valid colors to a specific subset of colors, e.g. Red
, Green
, and Blue
.
iota ๐
The iota
keyword in Go is a special feature that allows you to define a sequence of constants that increment by 1
. Sound useful? It’s not. It’s just cryptic syntactic sugar.
A smol-brained developer like me might make a few constants like this:
const (
Red Color = 0
Green Color = 1
Blue Color = 2
)
But a big-brained developer might save a few characters by using iota
:
const (
Red Color = iota
Green
Blue
)
Here’s the kicker: the iota
method uses the same amount of lines of code, but now I need to count on my fingers and toes to figure out the actual value of any of these constants.
const (
Red Color = iota
Green
Blue
Grey
Black
White
Yellow
Orange
Purple
Pink
Brown
Chartreuse
Mauve
)
What’s the value of Mauve
?
Additionally, there isn’t even support to quickly marshal these integers into strings (e.g. for debugging) without writing mountains of boilerplate code.
Frankly I just pretend iota
doesn’t exist and instead define string constants like a peasant:
type Color string
const (
Red Color = "Red"
Green Color = "Green"
Blue Color = "Blue"
)
Despite the verbosity, nothing is safe ๐
Believe it or not, I can still do this in Go:
type Color string
var carColor Color = "clearly not a color"
The compiler don’t care. The Color
type we made is just an alias for string
. Any string
is a valid Color
. Sure, I defined some constants, Red
, Green
, and Blue
, but they’re just constants that I hope and pray and beg my team to use.
I have no way to enforce this stuff at compile time. So now my only choice is to write runtime checks everywhere I use the colors:
switch color {
case Red:
// do happy thing
case Green:
// do other happy thing
case Blue:
// do other other happy thing
default:
return errors.New("wHY dIDn'T yOU uSe a vALID cOLoR???")
}
Eew, runtime.
If there’s one thing I hate more than indenting with spaces it’s doing literally anything at runtime.
How to make Go better ๐
I can’t believe I’m using TypeScript as an example of a language that does something well, but here we are. In TypeScript, you can define a sum type like this:
type Color = 'Red' | 'Green' | 'Blue'
Look at that. It’s simple. It’s elegant. It’s safe.
Sum types provide more type safety, more expressiveness, are easier to understand, all while being less verbose. It’s a win-win-win-win. If it weren’t for Go’s backward compatibility promise (which I love), I’d even rip out the stupid iota
keyword in addition to adding sum types.
๐จ๐จ BREAKING: TypeScript snatches defeat from the jaws of victory ๐จ๐จ ๐
TypeScript did it. They have beautiful beautiful sum types. They’re called unions in TypeScript, but they’re the same thing.
Then some galaxy-brained 10x developer decided it also needed an enum
keyword so we’d have 2 ways to accomplish the same thing:
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
Write Go.
Be grug.
Pray for sum types.