nil?, empty?, blank? in Ruby on Rails – what’s the difference actually?

Your ads will be inserted here by

Easy Plugin for AdSense.

Please go to the plugin admin page to
Paste your ad code OR
Suppress this ad slot.

There are plenty of options available. Let’s evaluate their usefulness and potential problems that they bring to the table.

nil?

  • Provided by Ruby
  • Can an be used on anything
  • Will return true only for nil
 nil.nil? # => true  false.nil? # => false  0.nil? # => false  "".nil? # => false 

empty?

  • Provided by Ruby
  • Can be used on collections such as Array, Hash, Set etc. Returns true when they have no elements.
[].empty? # => true  {}.empty? # => true  Set.new.empty? # => true 
  • but it is not included in Enumerable. Not every object which iterates and returns values knows if if it has any value to return

fib = Enumerator.new do |y|   a = b = 1   loop do     y << a     a, b = b, a + b   end end  fib.empty? # NoMethodError: undefined method `empty?' for #<Enumerator: 
  • It can also be using on Strings (because you can think of String as a collection of bytes/characters)
"".empty? # => true  " ".empty? # => false 
  • The problem with empty? is that you need to know the class of the object to be sure you won’t get an exception. If you don’t know if an object is an Array or nil then using empty? alone is not safe. You need tedious double protection.
object = rand > 0.5 ? nil : array object.empty? # can raise an exception  if !object.nil? && !object.empty? # doh...   # do something end 

This is where Rails comes with ActiveSupport extensions and defines blank? Let’s see how.

blank?

  • Provided by Rails
  • nil and false are obviously blank.
class NilClass   def blank?     true   end end  class FalseClass   def blank?     true   end end 
  • true obviously is not
class TrueClass   #   true.blank? # => false   def blank?     false   end end 
  • Array and Hash are blank? when they are empty? This is implemented using alias_method. You might wonder what about Set. This will be explained in a moment.
class Array   #   [].blank?      # => true   #   [1,2,3].blank? # => false   alias_method :blank?, :empty? end  class Hash   #   {}.blank?                # => true   #   { key: 'value' }.blank?  # => false   alias_method :blank?, :empty? end 
  • String#blank? behavior was changed compared to what ruby does with String#empty? to account for whitespaces
class String   BLANK_RE = //A[[:space:]]*/z/    # A string is blank if it's empty or contains whitespaces only:   #   #   ''.blank?       # => true   #   '   '.blank?    # => true   #   "/t/n/r".blank? # => true   #   ' blah '.blank? # => false   #   # Unicode whitespace is supported:   #   #   "/u00a0".blank? # => true   #   def blank?     # The regexp that matches blank strings is expensive. For the case of empty     # strings we can speed up this method (~3.5x) with an empty? call. The     # penalty for the rest of strings is marginal.     empty? || BLANK_RE.match?(self)   end end 

This is convenient for web applications because you often want to reject or handle differently string which contain only invisible spaces.

  • The logic for every other class is that if it implements empty? then that’s what going to be used. It’s interesting to see that the method and its behavior was documented fully here.
class Object   # An object is blank if it's false, empty, or a whitespace string.   # For example, +false+, '', '   ', +nil+, [], and {} are all blank.   #   # This simplifies   #   #   !address || address.empty?   #   # to   #   #   address.blank?   #   # @return [true, false]   def blank?     respond_to?(:empty?) ? !!empty? : !self   end 

!!empty? – is just a double negation of empty?. This is useful in case empty? returned nil or a string or a number, something different than true or false. That way the returned value is always converted to a boolean value.

Your ads will be inserted here by

Easy Plugin for AdSense.

Please go to the plugin admin page to
Paste your ad code OR
Suppress this ad slot.

!!true # => true  !!false # => false  !!nil  => false  !!0 # => true  !!"abc" # => true 

If you implement your own class and define empty? method it will effortlessly work as well.

class Car   def initialize     @passengers = []   end    def enter(passenger)     @passengers << passenger   end    def empty?     @passengers.empty?   end    def run     # ...   end end  car = Car.new car.blank? # => true  car.enter("robert")  car.blank? # => false 
  • No number or Time is blank. Frankly I don’t know why these methods were implemented separately here and why the implementation from Object is not enough. Perhaps for speed of not checking if they have empty? method which they don’t…
class Numeric #:nodoc:   #   1.blank? # => false   #   0.blank? # => false   def blank?     false   end end  class Time #:nodoc:   #   Time.now.blank? # => false   def blank?     false   end end 

present?

  • Provided by Rails
  • present? is just a negation of blank? and can be used on anything.
class Object   # An object is present if it's not blank.   def present?     !blank?   end end 

presence

Provided by Rails. Sometimes you would like to write a logic such as:

params[:state] || params[:country] || 'US' 

but because the parameters can come from forms, they might be empty (or whitespaced) strings and in such case you could get '' as a result instead of 'US'. This is where presence comes in handy.

Instead of

state   = params[:state]   if params[:state].present? country = params[:country] if params[:country].present? region  = state || country || 'US' 

you can write

params[:state].presence || params[:country].presence || 'US' 

The implementation is very simple:

class Object   def presence     self if present?   end end 

So which one should you use?

If you are working in Rails I recommend using present? and/or blank?. They are available on all objects, work intuitively well (by following the principle of least surprise) and you don’t need to manually check for nil anymore.

Was this helpful?

If you liked this explanation please consider sharing this link on:

  • your company’s Slack or other chat – for the benefit of your coworkers
  • Facebook & Twitter – for fellow developers who you are in touch with

Leave a Reply

Your email address will not be published. Required fields are marked *