nil?, empty?, blank? in Ruby on Rails - what's the difference actually?

… and check why 5600+ Rails engineers read also this

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

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.

!!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

You might also like