How to Avoid Truthiness in Ruby

Determining Truthiness of an expression?

You could try (true & value) == value. The part in parentheses seems to always return a boolean; if the value wasn't originally a bool, then it won't be equal to the result. A bool, however, will.

What evaluates to false in Ruby?

false and nil are the only ones:

http://www.ruby-doc.org/core-2.1.1/FalseClass.html

Rails provides present? which also includes empty strings and empty arrays: http://api.rubyonrails.org/classes/Object.html#method-i-present-3F

YARD convention for truthiness

Using anything other than Boolean would imply that you're doing some sort of special handling, like interpreting 0 as false or something less literal than true/false checking.

You can see the convention used in the YARD docs where Boolean represents both the TrueClass and FalseClass types. This type does not
exist in Ruby, however.

Trying to use .reduce to return true if there are truthy values else false if there are falsey values

You need to understand the difference between "truthiness"/"falsiness" and being true/false.

Ruby would evaluate everything that is not nil or false as truthy, so you can write:

puts 1 if 1

and it will puts 1.

In this assignment you're asked to use truthiness, so instead of comparing to true you can use ruby to do the conversion for you using double negation !!:

pry> [1, "2", nil, true, false].map{|e| !!e}
=> [true, true, false, true, false]

Also note that a block in reduce accepts two params - one is the current element and another one is accumulator - the result of interating over previous elements. Use both in the block, otherwise you'll be returning result depending only on the last element of the array.

With Ruby Booleans, what are you checking for if there are no equality statements?

This is a common paradigm in programming, not a Ruby abstraction. You are checking if something is truthy. In ruby in particular, everything is truthy except false and nil. Try it yourself in your console if you want to test this:

!!1 # => true
!!0 # => true
!![] # => true
!!{} # => true

...etc, whereas

!!false # => false
!!nil # => false

Important note: this is only the case for Ruby. Other languages have different rules. For example, in some languages 0 is falsy. It's important to learn these early on when learning a new language.

Best way to test if a variable is nil or false implicitly

def truthiness(value)
if value
"truthy"
else
"falsy"
end
end

puts "nil:", truthiness(nil) # falsy
puts "false:", truthiness(false) # falsy
puts "true:", truthiness(true) # truthy
puts "[]:", truthiness([]) # truthy
puts "{}:", truthiness({}) # truthy
puts "0:", truthiness(0) # truthy

I know you know Python, so I can say that:

In Python, None, False, and empty containers such as [], {}, and even 0 are all falsy.

In Ruby, nil and false are falsy, whereas most other things are truthy, even [], {}, and 0.

Make a NullObject evaluate to falsy in Ruby

I think you have only halfway adopted that pattern, and have not correctly adopted its spirit. My understanding is that the very purpose of the pattern is to avoid ||.

You should have some purpose for calling current_user || redirect_out, and that could be doing something with it, or getting some attribute of it. For example, suppose your code has:

(current_user || redirect_out).foo

When current_user is not an instance of Null::User, you wanted to call foo on it. In that case, what you should do is define Null::User#foo to be redirect_out (possibly followed by some more operations like foo on other classes).

class Null::User
def foo; redirect_out ... end
end

and in place of (current_user || redirect_out).foo, you should just do

current_user.foo

When current_user is not a Null::User instance, it will call foo. When it is such instance, then the redirect_out ... routine will be called on it.

Ruby Enumerable: first truthy value of a block

it does the job, but is the simplest way? Is it efficient compare to
simply using a each and caching the value?

Simplest way?

We can define this method :

def first_truthy_block(enumerable, &block)
enumerable.lazy.map(&block).find(&:itself)
end

Here in action :

array = [0,1,2,3,4,:x5,'abc']

puts first_truthy_block(array) { |x|
if x ** 2 > 10 then
"ARTWORK with #{x}!!!"
end
}
#=> ARTWORK with 4!!!

Could it be simpler?

  • enumerable is needed, it's the object you're working on.
  • lazy is needed, it wouldn't stop as soon as possible, and would throw an exception with :x5**2.
  • map is needed, you need to apply some method to your element
  • find is needed to extract one value at most out of your enumerable

With standard Enumerable methods, I don't see how it could be any simpler.

Is it efficient?

It is slower than your each method. It does basically the same thing and should have the same complexity but it does use more method calls and creates more objects :

require 'fruity'

def first_truthy_block_lazy(enumerable, &block)
enumerable.lazy.map(&block).find(&:itself)
end

def first_truthy_block_each(enumerable, &block)
enumerable.each do |item|
result = block.call(item)
return result if result
end
nil
end

big_array = Array.new(10_000){rand(4)} + [5] + Array.new(10_000){rand(20)} + [:x, :y, 'z']

compare do
_lazy_map do
first_truthy_block_lazy(big_array) { |x|
if x ** 2 > 10 then
"ARTWORK with #{x}!!!"
end
}
end

_each do
first_truthy_block_each(big_array) { |x|
if x ** 2 > 10 then
"ARTWORK with #{x}!!!"
end
}
end
end

fruity returns :

Running each test once. Test will take about 1 second.
_each is faster than _lazy_map by 3x ± 0.1

Why Treat 0 as True in Ruby?

I'm guessing that Matz wanted conceptual simplicity of "truthiness" as such - the only "false" values are false and nil. Period.

Using just false would be the cleanest but there is understandable need for including nil. To include the integer zero as a special case might open the mental floodgates of questioning truthiness of other types. What about strings, is "" false? And arrays, is [] false? And hashes, is {} false? Ad insanitum (see JavaScript)...



Related Topics



Leave a reply



Submit