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 fornil
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- Here you can learn more about enumerators
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 anArray
ornil
then usingempty?
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
andfalse
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
andHash
areblank?
when they areempty
? This is implemented usingalias_method
. You might wonder what aboutSet
. 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 withString#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 haveempty?
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 ofblank?
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