This is a continuation of my previous blog post on metaprogramming. In the previous post, we saw why we need metaprogramming. In this post, we will see what exactly this whole metaprogramming is all about. In the world of programming, the basic problem is that any general-purpose programming language is that it has its own limitations. If the language doesn’t have a metaprogramming model that is as pleasant and expressive as the language itself, then it will eventually frustrate the user. Nobody can design the perfect language, we get that! The people who manage these languages don’t allow the users to extend the language in generic ways. Not a bad thing altogether! This is done because a lot of people end up extending it in too many different ways and it becomes one big potpourri of nastiness. Coming back to the topic at hand, how exactly do we understand metaprogramming?
How does it work?
When we talk about metaprogramming, we usually think of programs that can generate programs. This is the broad idea! But within that general framework, there are subtle nuances. Metaprogramming usually works in one of three ways:
- The first way is to expose the internals of the run-time engine to the programming code through application programming interfaces (APIs). This means that we have a bunch of functions we call that will generate the code. We just have to call those functions and tell them that we need to code.
- The second way is the dynamic execution of expressions that contain programming commands. These commands are usually composed using strings. They can also be composed from other methods using arguments or context. These are the “programs that write programs” in the truest sense.
- The third way is to step outside the language entirely. General purpose program transformation systems are direct implementations of general metaprogramming. They accept language descriptions and can carry out arbitrary transformations on those languages. This allows metaprogramming to be applied to virtually any target language without regard to whether that target language has any metaprogramming abilities of its own.
Show Me An Example
Consider the following shell script:
#!/bin/sh echo '#!/bin/sh' > myProgram for i in $(seq 732) do echo "echo $i" >> myProgram done chmod +x myProgram
This is a simple example of a program generating another program. This script (or program) generates a new 733-line program that prints out the numbers from 1 to 732. This is not exactly the most efficient way to print out the numbers. It’s just a demonstrative example to showcase the nature of metaprogramming. To have some Inception-style fun, you can write a Python script that can generate this script. If you do that, then you will have a program that generates a program to generate a program.
The Reason Behind Its Existence
There are many reasons as to why we would need metaprogramming. It’s useful when you want to get around the limitations in the primary development languages. Usually, this sort of thing is done when there is a project requirement to use a particular language, and the use of a different language is not allowed. In this situation, people use metaprogramming with the development language as the target.
Another good thing is that it encapsulates domain-specific knowledge. What it means is that these languages are generally more domain-dependent, and so all the knowledge specific to the language can be enclosed. It also allows users to configure and program a system. Here, it is assumed that the user will not be likely be capable of modifying the program source directly, or might not even have access to that source. Examples include all sorts of configuration files. Depending on the needs, a custom config file format might be the best.
Is Metaprogramming A Good Idea?
It actually depends on two things: how domain-specific the meta-language is and how complex it is. Generally, domain-specific meta-languages are more justifiable. If you need domain independence, there are many fine choices available off-the-shelf. These are designed by folks whose domain expertise is programming languages. One of the biggest limitations of metaprogramming is the compile-time complexity. As your program gets more complex, it becomes really inefficient and time-consuming. Instead of writing programs to generate other programs, programmers usually just go ahead and write the program directly that needs to be generated.