Remember our earlier talk about ghost towns and marketplaces? If you want to manipulate language constructs, those constructs must exist at runtime. In this respect, some languages are better than others. Take a quick glance at a few languages and how much control they give you at runtime.
A program written in C spans two different worlds: compile time, where you have language constructs such as variables and functions, and runtime, where you just have a bunch of machine code. Because most information from compile time is lost at runtime, C doesn’t support metaprogramming or introspection. In C++, some language constructs do survive compilation, and that’s why you can ask a C++ object for its class. In Java, the distinction between compile time and runtime is even fuzzier. You have enough introspection at your disposal to list the methods of a class or climb up a chain of superclasses.
Ruby is a very metaprogramming-friendly language. It has no compile time at all, and most constructs in a Ruby program are available at runtime. You don’t come up against a brick wall dividing the code that you’re writing from the code that your computer executes when you run the program. There is just one world.
In this one world, metaprogramming is everywhere. Ruby metaprogramming isn’t an obscure art reserved for gurus, and it’s not a bolt-on power feature that’s useful only for building something as sophisticated as Active Record. If you want to take the path to advanced Ruby coding, you’ll find metaprogramming at every step. Even if you’re happy with the amount of Ruby you already know and use, you’re still likely to stumble on metaprogramming in the source of popular frameworks, in your favorite library, and even in small examples from random blogs.
In fact, metaprogramming is so deeply entrenched in the Ruby language that it’s not even sharply separated from “regular” programming. You can’t look at a Ruby program and say, “This part here is metaprogramming, while this other part is not.” In a sense, metaprogramming is a routine part of every Ruby programmer’s job. Once you master it, you’ll be able to tap into the full power of the language.
There is also another less obvious reason why you might want to learn metaprogramming. As simple as Ruby looks at first, you can quickly become overwhelmed by its subtleties. Sooner or later, you’ll be asking yourself questions such as “Can an object call a private method on another object of the same class?” or “How can you define class methods by importing a module?” Ultimately, all of Ruby’s seemingly complicated behaviors derive from a few simple rules. Through metaprogramming, you can get an intimate look at the language, learn those rules, and get answers to your nagging questions.
Now that you know what metaprogramming is about, you’re ready to dive in.