Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create an Object who act as a False in Ruby

Tags:

ruby

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?

like image 601
Tiago Peczenyj Avatar asked Jan 21 '13 18:01

Tiago Peczenyj


People also ask

Is False an object in Ruby?

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.

What evaluates to false in Ruby?

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.

How do you write not equal to in Ruby?

!= - The "not equal to" operator.

Is 0 true or false in Ruby?

Zero is a value, and ALL values in Ruby are evaluated to true, EXCEPT for FALSE and NIL.


2 Answers

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.

like image 70
Jörg W Mittag Avatar answered Sep 29 '22 11:09

Jörg W Mittag


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.

like image 29
tadman Avatar answered Sep 29 '22 12:09

tadman