1

With Ruby 2.4, I have this in part of my "if" statement

row_data.index{|x| DataHelper.my_function(x) } > num_var

Unfortunately, the above statement dies with an error if "row_data.index{|x| DataHelper.my_function(x) }" evaluates to nil. Is there any way to rewrite the above so that it would return "false" if "row_data.index{|x| DataHelper.my_function(x) }" evaluated to nil? I don't want to store the expression in a variable prior to my "if" statement because I might not need to even execute that statement if execution doesn't reach there. I feel like there's a one-liner but I don't know what it is.

2 Answers 2

5

Short circuit evaluations is the right way checking nil or false conditionals for two important reasons.

  1. Easy way out explicit conversions (to_s, to_i etc) can save you momentarily from raised exceptions/errors but at times can play the devil trick to break your conditionals when one of your compared values of the conditional is from - 0, "", [] and etc. Hence, explicit cares are to be taken considering your code might not last longer enough after a point of time.

    Ex. - 1

    if x.to_i > -1    
        puts x "is not a negative integer"
    else
        puts x "is a negative integer"
    end
    

    It can be dangerous as nil.to_i :=> 0 gets approved at if x.to_i > -1 logic check entering into conditional block with converted value (0 in case of nil.to_i).

    Probably, you won't mind for ex. - 1 to print a nil as: 0 is not a negative integer. How about this?

    if x.to_i   
        puts " 1/x is" 1/x
    end
    

    It can further raise ZeroDivisionError: divided by 0 for each x as nil and you have pay extra care in these cases. May be you did not want to entertain nil inside your block from the first place.

  2. Performance and CLEAN Code are two buzz words you hear everytime. Short circuit evaluations (&&) do not bother about succeeding conditionals if preceding condition is falsewhich makes conditionals execute faster. Additionally, It protects nil values entering into your conditional block and make it more vulnerable.

Answer to your ask:

if (not row_data.index{|x| DataHelper.my_function(x) }.nil?) && (row_data.index{|x| DataHelper.my_function(x) } > num_var)
   # do your if block here
   # this keeps nil away
else
   puts "row_data.index{|x| DataHelper.my_function(x) } is nil"
end
Sign up to request clarification or add additional context in comments.

3 Comments

I don't udnerstand how to apply this to my question.
put your integer variable: row_data.index{|x| DataHelper.my_function(x) } instead of a, and if it is nill, it will short circuit the loop and not execute the second part, if it is not nil, it will proceed to run (a > num_var)
this is the best answer, better than the accepted, short circuit evaluations needs to be in place for this case, or further bugs will go even deeper in code
3

You can take advantage of nil.to_i returning 0

if row_data.index{ |x| DataHelper.my_function(x) }.to_i > num_var
  # index is bigger than num_var
else
  # index is smaller or equal to num_var
end

Depending on what my_function and num_var represent, you may need to also account for the case of num_var == 0.

2 Comments

Good answer. You should add a space between the { and |.
This does work, but I think the other answer should be accepted for the reasons listed there. nil.to_i is problematic and the receiving function expects an integer not a truthy workaround. Single expression one-liners are great, but not if logic is hindered. Long story short, if you expect an integer, ensure you receive an integer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.