Source: unsplash.com

The defined? keyword in Ruby

An overview of the defined? keyword with a use case from the Ruby source code.. and an optimization tip!

Tech - RubyCademy
RubyCademy
Published in
3 min readSep 17, 2020

--

In this article, we’re going to explore the following topics:

  • the defined? keyword
  • defined? in the context of resolv-replace
  • defined? yield vs block_given?

The defined? keyword

In Ruby, the defined? keyword returns a string that represents the type of entity passed as an argument. Here is an exhaustive list of what you can pass to defined?

Here, we can see that defined? handles a maximum of cases. But some cases are more relevant than others. For example, let’s see how the resolv-replace library — available in the Ruby Standard Library — takes advantage of this keyword to handle a really “tricky” case.

defined? in the context of resolv-replace

This library simply monkey-patches (IP|TCP|UDP|SOCKS)Socket classes provided by the socket library to use the Resolv DNS resolver.

In the case of SOCKSSocket, the monkey-patching only intervenes when the Ruby interpreter is compiled with the --enable-socks flag. So let’s see how the resolv-replace library handles this tricky case

Notice the modifier-if line 10. Indeed, to choose whether to monkey-patch this class or not, the resolv-replace library simply checks if the SOCKSSocket constant is defined using the defined? keyword. Indeed, as seen in the previous section, SOCKSSocket is only defined if the Ruby interpreter is compiled using the --enable-flag.

So, as the class keyword is only syntactic sugar for class definition and class opening, then you can call a modifier-if to execute this code (or not).

Now let’s see how using defined? can positively impact the performance of your application.

defined?(yield) vs block_given?

If in your program you deal with a huge amount of blocks, then defined? yield can definitely become a real optimization for your program performance. Indeed, to check if a block is passed to your method, you normally use the Kernel#block_given? method

Here method_with_block_given checks if a block is passed as an argument by using Kernel#block_given?. If so, then yield is called and the block is executed. Otherwise, block_given? returns false and yield is never executed.

Ruby provides another way to achieve the same result: defined?(yield)

The main difference between these 2 expressions is that defined?(yield) is faster than Kernel#block_given?. Indeed, it’s a keyword when the block_given? is a method. So block_given? is slower because of the cost of the method call added to the cost of the Method Lookup Path.

Let’s generate benchmark-ips reports to see what’s the difference between defined?(yield) and block_given?

We can see that block_given? is 1.27x slower than defined?(yield).

But as seen in the above benchmark, we’re able to call block_given 9.897M times in a second. So keep in mind that this optimization is only relevant on a huge amount of block calls.

Conclusion

defined? isn’t the most popular keyword in Ruby. Nevertheless, in some situations, this keyword becomes a powerful asset to enhance your program performance or to handle tricky cases where a constant, method, etc... is conditionally loaded. Please feel free to share with us your experience with this keyword in the comments section.

Ruby Mastery

We’re currently finalizing our first online course: Ruby Mastery.

Join the list for an exclusive release alert! 🔔

🔗 Ruby Mastery by RubyCademy

Also, you can follow us on x.com as we’re very active on this platform. Indeed, we post elaborate code examples every day.

💚

--

--