[ruby] Checking if a variable is not nil and not zero in ruby

I am using the following code to check if a variable is not nil and not zero

if(discount != nil && discount != 0) 
  ...
end

Is there a better way to do this?

This question is related to ruby

The answer is


unless discount.nil? || discount == 0
  # ...
end

You could initialize discount to 0 as long as your code is guaranteed not to try and use it before it is initialized. That would remove one check I suppose, I can't think of anything else.


def is_nil_and_zero(data)
     data.blank? || data == 0 
end  

If we pass "" it will return false whereas blank? returns true. Same is the case when data = false blank? returns true for nil, false, empty, or a whitespace string. So it's better to use blank? method to avoid empty string as well.


if discount and discount != 0
  ..
end

update, it will false for discount = false


Yes, we do have a clean way in ruby.

discount.to_f.zero?

This check handles good amount of cases i.e. discount may be nil, discount may be int 0, discount may be float 0.0, discount may be string "0.0", "0".


I believe the following is good enough for ruby code. I don't think I could write a unit test that shows any difference between this and the original.

if discount != 0
end

unless [nil, 0].include?(discount) 
  # ...
end

From Ruby 2.3.0 onward, you can combine the safe navigation operator (&.) with Numeric#nonzero?. &. returns nil if the instance was nil and nonzero? - if the number was 0:

if discount&.nonzero?
  # ...
end

Or postfix:

do_something if discount&.nonzero?

if (discount||0) != 0
  #...
end

if discount.nil? || discount == 0
  [do something]
end

if (discount||0) != 0
  #...
end

class Object
  def nil_zero?
    self.nil? || self == 0
  end
end

# which lets you do
nil.nil_zero? # returns true
0.nil_zero?   # returns true
1.nil_zero?   # returns false
"a".nil_zero? # returns false

unless discount.nil_zero?
  # do stuff...
end

Beware of the usual disclaimers... great power/responsibility, monkey patching leading to the dark side etc.


You could initialize discount to 0 as long as your code is guaranteed not to try and use it before it is initialized. That would remove one check I suppose, I can't think of anything else.


if (discount||0) != 0
  #...
end

You can convert your empty row to integer value and check zero?.

"".to_i.zero? => true
nil.to_i.zero? => true

You could initialize discount to 0 as long as your code is guaranteed not to try and use it before it is initialized. That would remove one check I suppose, I can't think of anything else.


When dealing with a database record, I like to initialize all empty values with 0, using the migration helper:

add_column :products, :price, :integer, default: 0

I prefer using a more cleaner approach :

val.to_i.zero?

val.to_i will return a 0 if val is a nil,

after that, all we need to do is check whether the final value is a zero.


class Object
  def nil_zero?
    self.nil? || self == 0
  end
end

# which lets you do
nil.nil_zero? # returns true
0.nil_zero?   # returns true
1.nil_zero?   # returns false
"a".nil_zero? # returns false

unless discount.nil_zero?
  # do stuff...
end

Beware of the usual disclaimers... great power/responsibility, monkey patching leading to the dark side etc.


if (discount||0) != 0
  #...
end

ok, after 5 years have passed....

if discount.try :nonzero?
  ...
end

It's important to note that try is defined in the ActiveSupport gem, so it is not available in plain ruby.


Yes, we do have a clean way in ruby.

discount.to_f.zero?

This check handles good amount of cases i.e. discount may be nil, discount may be int 0, discount may be float 0.0, discount may be string "0.0", "0".


You could do this:

if (!discount.nil? && !discount.zero?)

The order is important here, because if discount is nil, then it will not have a zero? method. Ruby's short-circuit evaluation should prevent it from trying to evaluate discount.zero?, however, if discount is nil.


From Ruby 2.3.0 onward, you can combine the safe navigation operator (&.) with Numeric#nonzero?. &. returns nil if the instance was nil and nonzero? - if the number was 0:

if discount&.nonzero?
  # ...
end

Or postfix:

do_something if discount&.nonzero?

You could initialize discount to 0 as long as your code is guaranteed not to try and use it before it is initialized. That would remove one check I suppose, I can't think of anything else.


class Object
  def nil_zero?
    self.nil? || self == 0
  end
end

# which lets you do
nil.nil_zero? # returns true
0.nil_zero?   # returns true
1.nil_zero?   # returns false
"a".nil_zero? # returns false

unless discount.nil_zero?
  # do stuff...
end

Beware of the usual disclaimers... great power/responsibility, monkey patching leading to the dark side etc.


unless [nil, 0].include?(discount) 
  # ...
end

When dealing with a database record, I like to initialize all empty values with 0, using the migration helper:

add_column :products, :price, :integer, default: 0

def is_nil_and_zero(data)
     data.blank? || data == 0 
end  

If we pass "" it will return false whereas blank? returns true. Same is the case when data = false blank? returns true for nil, false, empty, or a whitespace string. So it's better to use blank? method to avoid empty string as well.


if discount.nil? || discount == 0
  [do something]
end

I believe the following is good enough for ruby code. I don't think I could write a unit test that shows any difference between this and the original.

if discount != 0
end

Alternative solution is to use Refinements, like so:

module Nothingness
  refine Numeric do
    alias_method :nothing?, :zero?
  end

  refine NilClass do
    alias_method :nothing?, :nil?
  end
end

using Nothingness

if discount.nothing?
  # do something
end

if discount and discount != 0
  ..
end

update, it will false for discount = false


unless [nil, 0].include?(discount) 
  # ...
end

You can convert your empty row to integer value and check zero?.

"".to_i.zero? => true
nil.to_i.zero? => true

I believe the following is good enough for ruby code. I don't think I could write a unit test that shows any difference between this and the original.

if discount != 0
end

class Object
  def nil_zero?
    self.nil? || self == 0
  end
end

# which lets you do
nil.nil_zero? # returns true
0.nil_zero?   # returns true
1.nil_zero?   # returns false
"a".nil_zero? # returns false

unless discount.nil_zero?
  # do stuff...
end

Beware of the usual disclaimers... great power/responsibility, monkey patching leading to the dark side etc.


unless [nil, 0].include?(discount) 
  # ...
end

Alternative solution is to use Refinements, like so:

module Nothingness
  refine Numeric do
    alias_method :nothing?, :zero?
  end

  refine NilClass do
    alias_method :nothing?, :nil?
  end
end

using Nothingness

if discount.nothing?
  # do something
end

I believe the following is good enough for ruby code. I don't think I could write a unit test that shows any difference between this and the original.

if discount != 0
end

You can take advantage of the NilClass provided #to_i method, which will return zero for nil values:

unless discount.to_i.zero?
  # Code here
end

If discount can be fractional numbers, you can use #to_f instead, to prevent the number from being rounded to zero.


You could do this:

if (!discount.nil? && !discount.zero?)

The order is important here, because if discount is nil, then it will not have a zero? method. Ruby's short-circuit evaluation should prevent it from trying to evaluate discount.zero?, however, if discount is nil.


ok, after 5 years have passed....

if discount.try :nonzero?
  ...
end

It's important to note that try is defined in the ActiveSupport gem, so it is not available in plain ruby.


You can take advantage of the NilClass provided #to_i method, which will return zero for nil values:

unless discount.to_i.zero?
  # Code here
end

If discount can be fractional numbers, you can use #to_f instead, to prevent the number from being rounded to zero.