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