I want to do this
lol = Klass.new(values)
unless lol
print "false"
end
lol.other_method # it is not nil or false, it is a Klass instance!
But lol, in this case, is not nil or false, but an object who can act as a false based on some internal value. I have this alternative
lol = Klass.new(values)
unless lol.to_bool
print "false"
end
But it is ugly IMHO.
I was thinking in extend the FalseClass or play with == but without success. Any Ideas?
In Ruby, true and false are boolean values that represent yes and no. true is an object of TrueClass and false is an object of FalseClass.
In Ruby only false and nil are falsey. Everything else is truthy (yes, even 0 is truthy). In some languages, like C and Python, 0 counts as false. In fact, in Python, empty arrays, strings, and hashes all count as false.
!= - The "not equal to" operator.
Zero is a value, and ALL values in Ruby are evaluated to true, EXCEPT for FALSE and NIL.
Unfortunately, this is not possible.
This is one of those annoying cases where Ruby is not object-oriented. In OO, it must be possible for one object to simulate another (in fact, depending on whom you ask, this is the very definition of OO – remember that OO came out of simulation), but it is not possible to build an object which simulates false
.
This is because, in Ruby, conditional control structures are baked into the language and don't translate into message sends, whereas in other OO languages they are just regular message sends (or at least translate into message sends, just like for
in Ruby translates into each
). For example, in Smalltalk, Booleans are actually implemented using the Church encoding of Booleans you know from Lambda Calculus, and translated to Ruby they look a bit like this:
class FalseClass
def if(&block)
# do nothing
end
def if_then_else(then_lambda, else_lambda)
else_lambda.()
end
def not
true
end
def and(&block)
self
end
def or(&block)
block.()
end
end
And TrueClass
is just the mirror image:
class TrueClass
def if(&block)
block.()
end
def if_then_else(then_lambda, else_lambda)
then_lambda.()
end
def not
false
end
def and(&block)
block.()
end
def or(&block)
self
end
end
And then, instead of something like
if 2 < 3 then foo end
if 2 < 3 then bar else baz end
You would have
(2 < 3).if { foo }
(2 < 3).if_then_else(-> { bar }, -> { baz })
# using the new keyword arguments in Ruby 2.0, it almost reads like Smalltalk:
class FalseClass
def if(then: -> {}, else: -> {})
else.()
end
end
class TrueClass
def if(then: -> {}, else: -> {})
then.()
end
end
(2 < 3).if(then: -> { bar }, else: { baz })
That way, you can easily create an object which simulates false
simply by implementing the respective methods.
In other cases, where some object really absolutely must be an instance of a specific class and not just speak the correct protocol, Ruby provides an escape hatch. For example, if a method really requires an Array
as an argument, then it will first try to call to_ary
to at least give you a chance to convert your object into an Array
. The same goes for to_str
, to_int
, to_proc
, to_float
etc. But there is no equivalent to_bool
protocol.
Short answer: Don't do this.
The long answer is that in Ruby there are only two things that evaluate as false: false
and nil
. Literally everything else evaluates as true.
Many applications depend on this behavior and will probably malfunction if you somehow manage to change this. It's like defining 1 to be an even number. It's going to cause problems.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With