Today, I want to start a new series of stories called: “ruby_cool_kid.rb — Meta Programming series”.
As of right now, I am reading a book called “Metaprogramming Ruby 2: Program Like the Ruby Pros” by Paolo Perrotta, where he talks about meta programming in Ruby and its advantages.
As concepts in meta programming are abstract, and sometimes hard to grasp, I am starting this series to try and explain the concepts I learned in an easy way that can be easier understood. Also, it would work as a challenge for me to see if I understood what I learned.
Please note that I will not be following Perrotta’s table of contents. I will follow my inspiration.
After this short purpose introduction, let’s dive into it!
Ruby, as opposed to static programming languages like Java or C, is a dynamic programming language.
Ruby is interpreted, not compiled, meaning that it can do at runtime what many static programming languages do at compilation, for example, defining new classes or methods. You might be wondering, what does dynamic dispatching have to do with all this.
Well, dynamic dispatching is the practice of dynamically calling a method based on data or information not known before. The main idea that makes the engine work is the method
In Ruby, methods are not called on objects but rather method’s names are sent to a receiver, usually the current object.
As Alan Kay, one of the fathers of the idea of OOP used to say referring to OOP: “The big idea is sending” (reference)
Based on this idea,
send is a method that helps us call object methods without having to use dot notation
Dynamic dispatching, takes advantage of this flexibility to call methods based on the data received. Let’s see an example.
Suppose you wanted to write a small program to congratulate your mom or dad on their birthday. We could write a little piece of code that would do so dynamically.
Of course, this is a very simple example that could have been done without dynamic dispatching, but it can be highly improved using Ruby’s tricks.
One of the goals or main definitions of meta programming is: Writing code that writes code, so, let’s try it.
In the previous example, there is a lot of duplicated code, that can be simplified by using
define_singleton_method (reference). It takes advantage of Ruby’s dynamic nature to define singleton methods. The code above is nice and works, but, what if we got confident and also wanted to congratulate our sister, our brother, our grandma? Let’s sharpen it:
As we can see, now
define_congratulations is called whenever the
BirthdayCongratulations class is instantiated. This method calls
define_singleton_method, which takes a method’s name and a block and creates a method just for our object. Then, by using dynamic dispatching, we can call such a method.
This has been a short concept example on how to use dynamic dispatching on Ruby. While it may not apply to all scenarios, it cannot be argued that it is a really powerful tool to have on our belt.
Also, take into account that despite being widely used by Ruby developers, send is not as good as it looks, as it exposes also private methods for the class. Use
public_send (reference) instead if you want to make sure your private methods remain private.
Did you think this code could not be further improved? It sure can! Follow me along for the next story ruby_cool_kid.rb — Metaprogramming series: Ghost methods 👻 where I will explain how missing methods can be found 😉
See you around!! 👋