To Be Or Not To Be in Ruby

Post Image

The questions that a programmer asks when learning a new language are akin to questions a first year philosophy student would ask: “What does it mean to exist?”, “What is true and what is false?”, “Can I make a decent salary after learning this?”. In today’s article I am going to answer one of the questions above for Ruby language:

“What does it mean to exist in Ruby?”

Suppose you have an object. You do not know what the object’s value is, but you just want to know whether the object resolves to true or not in a logical expression. Suppose you have no knowledge of the Ruby language but you have played around with some other languages before. Which operator would you use to fulfill the task?

I hope you picked the ! negation operator, because this article is not prepared for any other possibility.

irb(main)> !truthy_value
=> false
irb(main)> !falsey_value
=> true
irb(main)> !!truthy_value
=> true

Yes the handy good old bang works like it does in any other decent language and return the opposite of a logical value of an expression it precedes and is plenty useful in Ruby.

However what could be the actual value of falsey_value? In Ruby there are two possibilities: false and nil:

irb(main)> falsey = false
irb(main)> nilly = nil
irb(main)> !!falsey
=> false
irb(main)> !!nilly
=> false

Note: Beware of the zero though as unlike in many other languages it resolves to true in Ruby:

irb(main)> !0
=> false

Both false and nil logically resolve to false. Nil being the null reference type for Ruby and false representing a negatie logical value. How one would discern one from the other - for that Ruby provides a .nil? method to which only a nil object responds with true.

irb(main)> false.nil?
=> false
irb(main)> nil.nil?
=> true
irb(main)> truthy_value.nil?
=> false

Of course false and nil are drastic sates of non-existence, but what about less explicit states of non-existence. Suppose you have an Array representing your fridges contents and you would like to check whether there is any food left in there:

my_fridge = []
if my_fridge.____? 
    p 'Horray, there is food in the fridge'
else
    p 'Alright fellas, who ate my yoghurt?'
end

There are few ways to solve that dillema in plain Ruby.

One of them would be to utilise any? method available for any Enumerable object of which Array is an example. Without block provided it will return true if the collection contains any object that is not false or nil (you cannot eat a false logical value, unless our philosphy student allows you to do so).

my_fridge = []
if my_fridge.any? 
    p 'Horray, there is food in the fridge'
else
    p 'Alright fellas, who ate my yoghurt?'
end
=> 'Alright fellas, who ate my yoghurt?'

Suppose our philosophy student agrees that falsehood indeed can be consumed then we can provide a block to any? method to make it happen.

my_fridge = [false]
if my_fridge.any? { |food| food || !food }
    p 'Yummy, negative logical value up my tummy'
else
    p 'Alright fellas, who ate my yoghurt?'
end
=> 'Yummy, negative logical value up my tummy'

You can of course provide different condition in your block depending on your use case. Similarly we could ues Enumerable method detect which detects and returns the first element meeting the conditions described in a block.

my_fridge = [false]
if my_fridge.detect { |food| food == 'My goddamn yoghurt' }
    p 'Yoghurt - my precious'
else
    p 'Last chance! Where is HE?'
end
=> 'Last chance! Where is HE?'

But suppose you will eat lterally anything in your fridge regardless of what the philosophy student say, the method you would use would be .empty which returns true unless the array contains no elements, regardless of elements logical value. (Checking array.size == 0 would be another less elegant way to put it):

my_fridge = [false]
if my_fridge.empty?
    p 'There is nothing in my fridge'
else
    p 'There is something in my fridge'
end
=> 'There is something in my fridge'

my_fridge = []
if my_fridge.empty?
    p 'There is nothing in my fridge'
else
    p 'There is something in my fridge'
end
=> 'There is nothing in my fridge'

The very same method is also available for Strings and Hashes, and Sets:

irb(main)> [].empty?
=> true
irb(main)> ''.empty?
=> true
irb(main)> {}.empty?
=> true
irb(main)> {foo: 'bar'}.empty?
=> false
irb(main)> 'string'.empty?
=> false
irb(main)> Set[].empty?
=> true
irb(main)> Set[:my, :yoghurt].empty?
=> false

Your mind must now due to its software development conditioning be buzzing for the opposite of empty? that would show us whether the resource really exists. You are in for a disapointment since plain Ruby does not provide a direct opposite of that. A beloved Ruby library ActiveSupport however does.

The name of the method is present? and it works just as you would imagine

irb(main)> [].present?
=> false
irb(main)> ''.present?
=> false
irb(main)> {}.present?
=> false
irb(main)> {foo: 'bar'}.present?
=> true
irb(main)> 'string'.present?
=> true
irb(main)> Set[].present?
=> false
irb(main)> Set[:my, :yoghurt].present?
=> false

It also handles nil and false:

irb(main)> nil.present?
=> false
irb(main)> false.present?
=> false
irb(main)> true.present?
=> true

It has its opposite method in Active record called blank? I would recommend to use it instead of empty? as the former is not applicable for all possible objects that may appear in your output:

irb(main)> [].empty?
=> true
irb(main)> [].blank?
=> true
irb(main)> ''.empty?
=> true
irb(main)> ''.blank?
=> true
irb(main)> nil.empty?
NoMethodError (KABOOM!!!)
irb(main)> nil.blank?
=> true
irb(main)> false.empty?
NoMethodError (KABOOM!!!)
irb(main)> false.blank?
=> true

The resultant difference stems from how blank method is defined here.

The last existence of this article is exists? method of ActiveRecord.

Imagine you have a following ActiveRecord definitions:

class Knight < ApplicationRecord
  self.table_name = "knights"

  has_one :shield
end

class Shield < ApplicationRecord
  self.table_name = "shields"

  belongs_to :shield
end

This little method is directly linked to the object in a database and will ALWAYS check for presence of the record with an SQL query and return true or false depending on whether the object exists:

# triggers SQL query if shield not loaded
shield_id = knight.shield&.id 
# triggers a secondary query regardless of preloaded value - use with caution
knight.shield.exists? ? 'Defensive knight' : 'Knight who says Ni'

As mentioned above use this method with caution and only if you need the most current binary information about the existence of the object. This method is often cause of performance drops and N+1 queries (what those are and how to fight them is a story for another time).

As a last note in the article I would like to emphasise that due to Ruby’s metaprogramming and money patching properties your experience may vary as some programmers may be keen to override !~ or empty? methods for whatever reason.

Hope you enjoyed the read and me and our philosophy student will see you in the next article :).

Cheers,