You know how people talk about creating machines that can create more machines by themselves? Well, we already have machines that can create other machines. The concept of metaprogramming is just the technical side of it. Metaprogramming is the process of writing programs that can create other programs. It is one of the most underused programming techniques. The good thing is that it allows programmers to minimize the number of lines of code to express a solution, or it gives programs greater flexibility to efficiently handle new situations without recompilation. If it’s so good, then why isn’t it used everywhere? Why do we need it? Before we jump into the details of metaprogramming, let’s understand why we would consider it in the first place.
Compile-time vs Run-time
To start with, we can write programs that will pre-generate tables of data for use at run-time. The way things usually work in programming is that everything is generated at run-time, which can affect the overall speed of execution. If you pre-generate the data, you can improve the speed. For example, if you are creating a game and want a quick lookup table for the cube of all 8-bit integers, you have to calculate each cube value yourself and hand-code it. You can either have your program build the table at runtime, or write a program to build the custom code for the table before compile-time. While it may make sense to build the table at runtime for such a small set of numbers, other such tasks may cause program startup to be prohibitively slow. In such cases, writing a program to build static data tables is usually the best solution.
Let’s say you have a large application where many of the functions include a lot of boilerplate code. The “boilerplate code” refers to the necessary code that is required for the overall structure. These things are usually dictated by the language. For example, cars are manufactured, the wheel can be thought of as the boilerplate. Different models of the same company can differ in design and features, but all of them need wheels. The features of the wheel don’t change for different models.
Now do we need to think about creating this boilerplate code every time? You can just create a mini-language that will create the boilerplate code for you and allow you to code only the important parts. That would be nice, right? Now, if you can, it’s best to abstract out the boilerplate portions into a function. What this means is that, you should be able to make a simple function call and that function will do everything for you. But more often that not, the boilerplate code isn’t all that pretty.
It Ain’t Pretty!
There are many situations we can think of when boilerplate code isn’t nice and pretty. May be there’s a list of variables to be declared in every instance, or maybe you need to register error handlers, or maybe there are several pieces of the boilerplate that have to have code inserted in certain circumstances. All of these make a simple function call impossible. Going back to our car and wheel example, It’s like trying to customize the wheel for different models.
If you have the a plant that produces the same wheel for all the models, you cannot create any customized wheels. In such cases, it is a good idea to create a mini-language that allows you to work with your boilerplate code in an easier fashion. This mini-language will then be converted into your regular source code language before compiling. So instead of blindly manufacturing wheels, we can have a robot and we can tell the robot what to do. This way, we have something that controls the production of the wheels according to our needs and requirements.
A lot of programming languages make you write really verbose statements to do really simple things. We’ve all been there! Code-generating programs allow you to abbreviate such statements and save a lot of typing, which also prevents a lot of mistakes because there is less chance of mistyping. As languages acquire more features, code-generating programs get less appealing. What is available as a standard feature in one language may be available only through a code-generating program in another language. However, inadequate language design is not the only reason for needing code-generating programs. Easier maintenance is also a reason.
Now that we know why we would consider metaprogramming, we will discuss what exactly it is in our next blog post.