Disclaimer: I am not inherently against the paleo diet, nor is this article an attempt at bashing GoLang. I only hope to share a simple and powerful truth that I feel is often undervalued.
I have had many an argument with fellow software engineers over a very simple and powerful concept: metaprogramming. The debate rages from, “it makes code too hard to read!” and, “it is impossible to debug”, all the way to, “it shouldn’t be used because my mom said so.” Okay… really, my mom didn’t say so; but you see what I am getting at.
We all have opinions; hopefully most of them are grounded in some truth. So what makes engineers opinion’s about metaprogramming so passionate, so much so that Google deliberately chose to trek back into the stone-ages by removing nearly all forms of “advanced” metaprogramming from GoLang? I feel it all stems from one simple and flawed thought: metaprogramming can be complex and hard to understand… but the irony is that it isn’t generally complex or hard to understand, and is already used everyday by nearly every software engineer around the world.
The birth of metaprogramming, like most innovations, came from necessity. Developers got tired of punching holes in punch cards, that were essentially direct byte-by-byte instructions for the computer to consume. So the Assembly language was invented (yes, I may have skipped a step or two). Assembly was certainly a step up from punch cards, but still difficult to work with because it was too direct and too close to the hardware. Then came higher level languages such as C, LISP, etc... But wait… did you miss it? Metaprogramming was already being used. As soon as the direct byte-to-byte input of programs grew to something less byte-to-byte, metaprogramming was born. Assembly was this birth.
You might be thinking, “What? Assembly has nothing to do with metaprogramming”, but you would be incorrect in that thought. Metaprogramming in essence is about closing the gap between how us humans think and how the computer operates. All attempts at closing this gap since the dawn of the machine have been iterations on a single concept: metaprogramming.
Humans by nature are lazy. I have even heard rumors that laziness is the master of all invention. I don’t know about all that, but I do know when you have thousands, or tens of thousands of manual instructions in a single program, it quickly scales outside the realm of “simple”. Ironically the problem of simplicity is one of the problems GoLang was designed to solve… and in my opinion failed miserably at.
C exists primarily because Assembly was difficult, tedious, and hard to scale. Assembly wasn’t simple to scale or understand. This was true to such an extent that C was built with a preprocessor at the forefront to allow the use of macros for code generation and segregation (which wasn’t new, macros were used in Assembly before C came along). Every step in “innovation” since then (when processing power enabled such innovation) has been an attempt at closing the gap between the machine and the human with a single powerful tool: metaprogramming. GoLang’s deliberate attempt at stripping generics and macros from the language is a step backwards, not a step forward towards simplicity; a paleo approach if you will.
Metaprogramming is, and has been, heavily used via the use of preprocessors, compilers, macro languages, code generation, transpiling, reflection, overloading, polymorphism, functional programming, etc… The world will not stop along this path simply because some developers claim that lack of metaprogramming makes code simpler and easier to understand (tell that to the person attempting to implement a generic class such as a simple List in GoLang).
The next question I have is: simpler for whom? Anyone who claims to be a software engineer needs to understand metaprogramming. To understand metaprogramming is to understand our own nature, and how we differ from machines. Such understanding must not be lost on any good developer, because if it is, they probably aren’t a good developer.
Soon the world will see new innovations in metaprogramming, such as AI, where we simply tell the computer what we want at a high-level and it will generate the code necessary. This will be yet another iteration in metaprogramming. As with all things in life “everything in moderation”; metaprogramming should be used daily, as much as needed to ease software development by bringing the machine closer to the human. It isn’t going away, and instead should be embraced and fully understood by all developers everywhere. Anything less would be an irresponsible step at widening the gap between the machine and the human.
So next time you hear someone argue against metaprogramming, hand them a punch card, and an index of punch patterns and what machine instructions they translate into.