The proposal for generics in Go was accepted today. This, and other things,
There's a trend I've noticed in Go community. It's a mindset that emerges at all levels - from junior developers all the way up to the thoughtleader "personalities" of the community, and... I don't like it.
It's a point of view that implies, and occasionally outright states, that "abstraction is wrong", that "being too clever" is "not idiomatic" in Go. That it's bad to be smart.
I'm going to call them Luddites for now, because it's more arresting, but it really represents the encroaching of anti-intellectualism into our work. Let me give a couple of examples.
The Difference Of Squares
I like Exercism, an online platform for learning a language. Solve problems, review your code, compare it to others. Great fun.
Fun problem: find the difference between the square of the sum of the numbers from 1 to n
, and the sum of the squares from 1 to n
. Sadly, my first take on this problem in Go has been erased by the sands of multiple Exercism platform upgrades, but originally it looked a little something like this:
package diffsquares
func SquareOfSum(num int) int {
sum := 0
for i := 0; i <= num; i++ {
sum += i
}
return sum * sum
}
func SumOfSquares(num int) int {
sum := 0
for i := 0; i <= num; i++ {
sum += i * i
}
return sum
}
func Difference(num int) int {
return SquareOfSum(num) - SumOfSquares(num)
}
Shamelessly borrowed from this solution.
Well, I'm a little mathsy in my spare time, so I thought there might be a way to do this without so much looping involved. Sure enough, these two numbers can be reached by using formulae for square pyramidal numbers and triangular numbers. Leading to something like this:
package diffsquares
func SquareOfSum(n int) int {
x := (n * (n + 1) / 2)
return x * x
}
func SumOfSquares(n int) int {
x := (n * n * n) * 2
y := (n * n) * 3
return (x + y + n) / 6
}
func Difference(n int) int {
return SquareOfSum(n) - SumOfSquares(n)
}
And in the comments I wrote something to the effect that this was a neat maths hack that simplified the solution.
Then somebody commented. Which is great, and I'm always glad to have people picking apart my shady code. But what they said was not so great. I'm forced to paraphrase as, sadly, that version of the comments system is now long gone. But it went something like this:
This is bad Go code. In Go we favour simplicity and readability, not weird maths hacks. This would be much better written as a pair of
for
loops.
Eh?????
Go 2.0 Generics
So today the proposal for generics in Go got one step further towards appearing in the language - it was accepted! Sure, some people have some problems with the specifics, but I want to focus on a vocal minority (well, I hope they're a minority) who oppose generics.
There's been some reaction:
And the one that sparked this rant...
(sadly I can't link you to this tweet because, after I told the author it was stupid, they deleted it. And then blocked me. Shrug.)
followed by:
They went on a bit, but they deleted it for a reason so let's not pile on. But it's not the first time I've seen or heard this sort of opinion:
Go is meant to be simple! Generics aren't simple.
Go doesn't need generics, I'm happy writing Go without generics. Why do I need generics now?
Go is meant to be readable! I can't read generics, but I can understand a nice
for
loop.I can't understand code written with generics, so I like Go.
Seems familiar? That's why I'm writing this?
Do You Believe In Magic?
The maths I wrote for the Exercism exercise isn't complicated. In fact, I'm pretty sure you can read it out loud and understand it. What you might not understand is why it works. Fine. Maybe it seems like "magic" to you - no, you don't believe in magic. But you do know that "magic" in your code is A BAD THING, or at least that's what someone told you once.
But, to quote Arthur C. Clarke
Any sufficiently advanced technology is indistinguishable from magic.
It's not actually magic, it's not even mathemagic. It's just mathematics. You can go to those Wikipedia pages and read them and - boom! - you now know why it works. It happens to be faster that looping, but more importantly it's correct - it's simplified the looping down to single formula.
Yes, that's right, I'm claiming that it's simpler. Loops are not simple. Loops are, to be frank, a quite hard. To read them you have to move your eyes around a bit, walk the code, jump back to the top again, repeat... Sure, you may be more familiar with loops, but that's because you see them every day in Go.
You wouldn't write a loop to add two numbers together? Or to multiply them? This is no different. Things don't become complicated because you're being clever; things become complicated because you're being dumb.
So Why The Generics Hate?
There's a lot of talk about generics adding complication. No, they add another tool. You don't like it, you don't use it. The problem with this particular tool is that developers are remembering the garbage code they've seen written using generics in all the wrong ways. Prematurely abstracted supertypes that have no basis in reality, increase complexity, introduce incidental coupling where there should be none or decouple things that should be coupled. They remember this code because they wrote it all ten years ago in Java and now they're worried it's going to be all over Go.
Well, it probably will. But I reckon there's just as much garbage Go being written right now by folks who don't know basic arithmetic, how HTTP works, or when you should or shouldn't be using interface{}
. They will move on to writing garbage prematurely abstracted Go with generics, never write a test first, change job every year, and get called rockstars or 10x developers. I'd try and avoid them and their codebases.
Or perhaps you're new to programming per se, or Go is the first typed language you've used. You're probably used to the playground fights about "lol no generics" and have grown up defining your language, and yourself, as "anti-generic". A sort of weird parochial view of programming - "we don't need your fancy city generics here in Goville".
Both these views are understandable, but nevertheless pretty dumb.
Consider the parable of the Blub programmer by Paul Graham. Don't consider all of it as parts are dumb and out of date, but ask yourself, do I think that generics are useless and unnecessary because I just don't understand them? All those other languages and programmers using generics - are they just being fancy for no reason? Are they just showing off and making code that nobody can read or test? Apply this thinking to all the features and techniques you can think of - do you think I have a deployment pipeline that runs automated tests at work because I'm showing off? Because I'm brainwashed by the Accelerate people and I should really just be FTPing the code to a server somewhere?
Programming is Abstraction
To finally claim that abstraction is dangerous and wrong... please. Heaven help me please - abstraction is the very soul of programming. If we weren't writing our own abstractions when we write code we'd be sitting there staring at a 10000 line main
function wondering what on earth this thing did.
Abstraction is our only tool in fighting complexity. Well, the only one that works as the documentation is out of date. We use it with our training and our intelligence and hope to hell we make something beautiful at the end.
Beauty is more important in computing than anywhere else in technology because software is so complicated. Beauty is the ultimate defense against complexity.
-- Edsger W. Dijkstra
Anything - ANYTHING - that gives us another way to abstract in our software is undeniably a VERY GOOD THING.
And generics are just another tool for abstraction. You might not understand it when you first see it - or second, or third. You might not understand how or when to use it. But that doesn't make it more complicated. It's not less readable. It's just making a demand that you learn something new and - as always - have the good taste and intelligence to use it well.
Read a Damn Book
Here's some takeaways for you to angrily repost on Twitter:
If you don't understand it, then you should try and learn it. You work in a knowledge based industry.
If you don't understand it and don't want to learn, then I'd seriously consider my career options: you work in a knowledge based industry.
If you do understand it, but somehow think that it's bad because other people won't understand it or will use it badly - well, I'm sorry, but that's all of programming. Stupid is as stupid does, and if you're going to use these new tools to make your code unreadable, that's on you - not the tools.
Of course, you don't think that. You think that these features are great but should be reserved for "senior" programmers who "know how to use them". You want a language that your underlings can't make mistakes in? This carries the idea that is still prevalent in a lot of places that Go is a "training wheels" language, designed to prevent you from making mistakes. Which is crap. It's minimal and opinionated, it's not idiot proof.
Conclusion
Programming is best when you use all the tool of abstraction at your disposal - functions, arithmetic, naming, modules and yes generics - to reduce complexity. Making things simple is hard - you need to learn, write and think hard.
Complaining about "clever" language features is like moaning about anonymous functions or irrational numbers. Stop being dumb, and stop promoting dumbness.
P.S. You should also probably do TDD.