The Mythical Ruby Splat
Most Rubyists are aware of variable length arguments in a method definition. For example:
Just as a refresher, the * operator, commonly known as a “splat,” collects the arguments into an array object. So in the example above, the variable
*names is an array object, which means it can be used just like any other array:
What blew my mind recently was stumbling across Ruby code where the name for the “splat” was missing. I assure you that this is valid Ruby code:
Kinda interesting, huh?
But when would you ever use this? Consider the slightly contrived example below:
AdminUser is a subclass of
User using Active Record’s built-in single table inheritance.
Let’s assume that the user with ID of 1 is an instance of the
User class and the user with ID of 42 is an instance of the
Everything is hunky-dory until we need to change
Let’s say requirements change and users are now active for a particular period.
User#active? now takes a start date and end date to determine if the user is active during that period:
The problem is that our
AdminUser#active? does not take any arguments and therefore will generate a runtime error if called with
AdminUser#active? to work just like
User#active? but without updating the
AdminUser class. Otherwise, every time we change the
User class we’ll have to go and update the
AdminUser class. The fix is to have originally defined
AdminUser like so:
AdminUser#active? will cause it to safely ignore any arguments passed in. Going through the whole example again,
AdminUser are defined as:
Now let’s redefine
User#active? to take into account a start date and end date:
Using methods with an unnamed “splat” is probably something you won’t do too often, but it can be useful in defining your intentions.
Looking at the
AdminUser class, the
#active? method clearly defines that its arguments are not used versus other possible implementations like
def active?(start_date, end_date),
def active?(*unused) or
You can clearly see with
active?(*) that the arguments provided will be ignored, whereas the other three you would need to dig into the implementation to verify.