When to Use Nil, Blank, Empty

When to use nil, blank, empty?

  • nil? - checks to see if variable is referencing an object or not

  • empty? - may be used to check on various object types like empty string "" or empty array []

  • blank? - checks for nil? or empty?.

Difference between .nil?, .blank? and .empty?

In Ruby, nil in an object (a single instance of the class NilClass). This means that methods can be called on it. nil? is a standard method in Ruby that can be called on all objects and returns true for the nil object and false for anything else.

empty? is a standard Ruby method on some objects like Arrays, Hashes and Strings. Its exact behaviour will depend on the specific object, but typically it returns true if the object contains no elements.

blank? is not a standard Ruby method but is added to all objects by Rails and returns true for nil, false, empty, or a whitespace string.

Because empty? is not defined for all objects you would get a NoMethodError if you called empty? on nil so to avoid having to write things like if x.nil? || x.empty? Rails adds the blank? method.


After answering, I found an earlier question, "How to understand nil vs. empty vs. blank in Rails (and Ruby)", so you should check the answers to that too.

How to understand nil vs. empty vs. blank in Ruby

.nil? can be used on any object and is true if the object is nil.

.empty? can be used on strings, arrays and hashes and returns true if:

  • String length == 0
  • Array length == 0
  • Hash length == 0

Running .empty? on something that is nil will throw a NoMethodError.

That is where .blank? comes in. It is implemented by Rails and will operate on any object as well as work like .empty? on strings, arrays and hashes.

nil.blank? == true
false.blank? == true
[].blank? == true
{}.blank? == true
"".blank? == true
5.blank? == false
0.blank? == false

.blank? also evaluates true on strings which are non-empty but contain only whitespace:

"  ".blank? == true
" ".empty? == false

Rails also provides .present?, which returns the negation of .blank?.

Array gotcha: blank? will return false even if all elements of an array are blank. To determine blankness in this case, use all? with blank?, for example:

[ nil, '' ].blank? == false
[ nil, '' ].all? &:blank? == true

nil v/s empty in ruby

Apparently @stores is not nil but initialized to an empty array [].

So !@stores.nil? is true because @stores.nil? is false. I'm not familiar with logger.info so I'm not sure why it prints nil for the third line. empty? returns true if there is no element in the array.

Should I use `.blank?` in a view of performance?

Theory

All three methods have various realizations for various classes:

  1. :nil?:

    # NilClass
    def nil?
    true
    end

    # Object
    def nil?
    false
    end
  2. :empty?:

    # String, Array
    def empty?
    if self.size == 0
    true
    else
    false
    end
    end
  3. :blank?:

    # FalseClass, NilClass
    def blank?
    true
    end

    # Object
    def blank?
    respond_to?(:empty?) ? empty? : !self
    end

    # TrueClass
    def blank?
    false
    end

    # String
    def blank?
    self !~ /[^[:space:]]/
    end

As you may see the various classes implement various methods style. In case of String class it takes time of a single Regexp, in case of Object, including Hash, and Array it takes time of call to :respond and return a value nil or not Object. The seconds are just operations that takes time similar to :nil?. :respond? method checks the presense of the :empty? method that takes theoretically slight more times than two times
to :empty?.

Investigations

I wrote simple script that simulates the behaviour of those methods, and calculates execution time of them:

#! /usr/bin/env ruby

require 'benchmark'

obj = Object.new
array = []
empty_string = ''
non_empty_string = ' '

funcs =
[ proc { empty_string.empty? },
proc { non_empty_string.empty? },
proc { obj.nil? },
proc { nil.nil? },
proc { true },
proc { respond_to?(:empty?) ? empty? : !self },
proc { array.respond_to?(:empty?) ? array.empty? : !array },
proc { non_empty_string !~ /[^[:space:]]/ } ]

def ctime func
time = 0
1000.times { time += Benchmark.measure { 1000.times { func.call } }.to_a[5].to_f }
rtime = time /= 1000000
end

funcs.each {| func | p ctime( func ) }

And results:

# empty String :empty?
# 4.604020118713379e-07
# non_empty String :empty?
# 4.5903921127319333e-07
# Object :nil?
# 5.041143894195557e-07
# NilClass :nil?
# 4.7951340675354e-07
# FalseClass, NilClass, TrueClass :blank?
# 4.09862756729126e-07
# main :blank? ( respond_to returns false )
# 6.444177627563477e-07
# Array :blank? ( respond_to returns true )
# 6.491720676422119e-07
# String :blank?
# 1.4315705299377442e-06

As you may see, obvious champion from the end of table in case of speed is method :blank? of String class. It has execution time descreased in 3-4 times against an simple empty? method of a class. Object's :blank? method has only 1.5 times execution time degradation. Note, that :respond_to method in it has just a few time to execute, becase as far as I see the ruby interpreter caches the result of its execution. So, conclusion. Try to avoid using String's .blank? method.

Additional, if you need to know how to use the methods see here.

Testing for empty or nil-value string

The second clause does not need a !variable.nil? check—if evaluation reaches that point, variable.nil is guaranteed to be false (because of short-circuiting).

This should be sufficient:

variable = id if variable.nil? || variable.empty?

If you're working with Ruby on Rails, Object.blank? solves this exact problem:

An object is blank if it’s false, empty, or a whitespace string. For example, "", " ", nil, [], and {} are all blank.

Return string if data is empty, nil or blank?

check if you have presence available in your rails version. If it is, you can do the following

<%= f.text_area :comment, placeholder: @response.followup.presence || "Would you like to add a note?" %>

If it's not available, you can choose one of the following

  1. use a decorator/presenter (i think this is overkill)
  2. set the value of the placeholder in the controller

    @response.followup = 'Would you like to add a note?' if response.blank?

  3. use a ternary operator in the view

    <%= f.text_area :comment, placeholder: (@response.followup.blank? ? "Would you like to add a note?" : @response.followup) %>

Ruby when nil or empty string

You can use activesupport's Object#presence method, like this:

foo = params[:customer][:language].presence || 'es'

Check if not nil and not empty in Rails shortcut?

There's a method that does this for you:

def show
@city = @user.city.present?
end

The present? method tests for not-nil plus has content. Empty strings, strings consisting of spaces or tabs, are considered not present.

Since this pattern is so common there's even a shortcut in ActiveRecord:

def show
@city = @user.city?
end

This is roughly equivalent.

As a note, testing vs nil is almost always redundant. There are only two logically false values in Ruby: nil and false. Unless it's possible for a variable to be literal false, this would be sufficient:

if (variable)
# ...
end

This is preferable to the usual if (!variable.nil?) or if (variable != nil) stuff that shows up occasionally. Ruby tends to wards a more reductionist type of expression.

One reason you'd want to compare vs. nil is if you have a tri-state variable that can be true, false or nil and you need to distinguish between the last two states.



Related Topics



Leave a reply



Submit