Why don't TrueClass and FalseClass share a common Boolean ancestor

#1

Both TrueClass and FalseClass inherit directly from the Object class.
They share a common structure and do very similar jobs. So why don’t
they share a common parent between them and Object? BooleanClass
perhaps?

I wanted to test some input for true or false and thought
true.class.ancestors and false.class.ancestors would give me a shared
parent class to test for rather than have to check for each
independently.

An academic question really, that piqued my curiosity and seemed more
strange the deeper I looked. It got me looking into the C code behind
Ruby for the first time (which can’t be a bad thing), where I was struck
by the similarities between the two object structures.

From the positioning of the comments*:

TrueClass methods appear to be defined by:

true_to_s, true_and, true_or, true_xor.

FalseClass methods appear to be defined by:

false_to_s, false_and, false_or, false_xor

Then there are some other methods that seem to be hung on the end and I
assume from the names are associated with the core ruby space:

rb_true, rb_false, rb_obj_match, rb_obj_not_match, rb_obj_cmp

Which look ripe to be placed within a BooleanClass name space to me.

Looking at https://github.com/ruby/ruby/blob/trunk/object.c lines 1107
to 1342.

So just wondered if anyone knew why there isn’t a dedicated parent class
to TrueClass and FalseClass.


  • My knowledge of C is non-existent, so please excuse any fundamental
    misunderstanding of the code that I may have made. For example, I’m
    failing to find where Qtrue and Qfalse are defined, and both seem to
    hold the key to understanding true and false within the ruby code.
#2

This can only be properly answered by a language designer, so here goes
an
improper conjecture :).

As you know all objects in Ruby are booleans. In this interpretation of
the
situation TrueClass is semantically no different than String: the true
singleton and an empty string are as true objects as any other.
Therefore
it needs no extra hierarchy.

#3

Hi,

There’s nothing true and false commonly share, thus no Boolean class.
Besides that, in Ruby, everything behave as Boolean value, as Xavier
mentioned in [ruby-talk:406208].

          matz.

In message “Re: Why don’t TrueClass and FalseClass share a common
Boolean ancestor”
on Wed, 27 Mar 2013 20:56:24 +0900, “Rob N.” removed_email_address@domain.invalid
writes:

|Both TrueClass and FalseClass inherit directly from the Object class.
|They share a common structure and do very similar jobs. So why don’t
|they share a common parent between them and Object? BooleanClass
|perhaps?
|
|I wanted to test some input for true or false and thought
|true.class.ancestors and false.class.ancestors would give me a shared
|parent class to test for rather than have to check for each
|independently.
|
|An academic question really, that piqued my curiosity and seemed more
|strange the deeper I looked. It got me looking into the C code behind
|Ruby for the first time (which can’t be a bad thing), where I was struck
|by the similarities between the two object structures.
|
|From the positioning of the comments*:
|
|TrueClass methods appear to be defined by:
|
| true_to_s, true_and, true_or, true_xor.
|
|FalseClass methods appear to be defined by:
|
| false_to_s, false_and, false_or, false_xor
|
|Then there are some other methods that seem to be hung on the end and I
|assume from the names are associated with the core ruby space:
|
| rb_true, rb_false, rb_obj_match, rb_obj_not_match, rb_obj_cmp
|
|Which look ripe to be placed within a BooleanClass name space to me.
|
|Looking at https://github.com/ruby/ruby/blob/trunk/object.c lines 1107
|to 1342.
|
|So just wondered if anyone knew why there isn’t a dedicated parent class
|to TrueClass and FalseClass.

* My knowledge of C is non-existent, so please excuse any fundamental
misunderstanding of the code that I may have made. For example, I’m
failing to find where Qtrue and Qfalse are defined, and both seem to
hold the key to understanding true and false within the ruby code.
Posted via http://www.ruby-forum.com/.
#4

On 27 March 2013 11:56, Rob N. removed_email_address@domain.invalid wrote:

Both TrueClass and FalseClass inherit directly from the Object class.
They share a common structure and do very similar jobs. So why don’t
they share a common parent between them and Object? BooleanClass
perhaps?

I’d be curious to know what exactly you’re testing, and why you need
to deal with true and false as specific values.

Here’s my justification, although if anyone finds flaws, please point
them out! (There might be better arguments than this.)

All objects that are not nil or false evaluate as truthy.

s = “foo”
puts “You’ll see this.” if s

The presence of a Boolean starts to suggest code like this:

do_something(arg) if arg.class == Boolean

This goes against duck typing. Let’s look at Integer, for instance.
Integer wraps Fixnum and Bignum, but you shouldn’t really ever do
this:

process_number(arg) if arg.is_a?(Integer)

Instead you should allow objects to indicate they have Integer
representations, without forcing them to subclass:

class BankBalance # Note this does not subclass Integer
def initialize(amount)
@amount = amount
end

def to_int
  @amount
end

end

(First example off the top of my head. Might have problems, but treat
as illustrative.)

Now any code that wants to deal with some notion of an integer can
rely on BankBalance instances without any checks:

do_something(number.to_int)

BankBalance doesn’t implement an Integer so it shouldn’t subclass
Integer, but by defining to_int, the class is saying it can act like
one in a certain way; the net result being that code can skip checking
implementation details.

Note that to_int is different from to_i. to_i is an explicit
conversion to an integer, but to_int is intended to give the message:
“I act like an Integer.” Similarly: to_str for acting like a String,
distinct from explicit conversion with to_s.

So with that in mind, you might imagine Boolean-ish duck typing based
on something like to_bool, right?

class TrueClass
def to_bool
true
end
end

class FalseClass
def to_bool
false
end
end

def NilClass
def to_bool
false
end
end

But then (Basic)Object would need to define it so that all non-nil,
non-false objects come back as truthy:

class Object
def to_bool
true
end
end

But then you might hit a lot of confusion if something decides to
define to_bool as false: suddenly Ruby’s contract of “non-nil,
non-false values are truthy” can have extra clauses added to it. And,
what have you gained?

if arg.to_bool
# do stuff
end

Ruby gives you this:

if arg
# do stuff
end

So I guess to summarise the above:

  • Duck typing.
  • It’s built in for you implicitly.
#5

Thank you for the responses.

So FalseClass is the special object as it behaves differently to other
objects in boolean operations,

TrueClass is just a very simple object that in boolean operations
behaves like other objects.

Looking at it on that level it makes sense not to have a common
ancestor.

In response to Adam: For some background, I’m working on an gem I’ve
created to simplify creating rules for arrays of objects. Up until now
the logic has been simple, but I wanted to add some functions (sum,
average, and count to start with).

So if I added a rule ‘sum(:some_method) > 4’, it would pass when
some_method was called on all the objects in the array, and the
collected results added up to more than 4.

The code is here:

https://github.com/reggieb/array_logic/blob/master/lib/array_logic/rule.rb

They we’re not failing very gracefully if the method being called did
not return a number, and I was working on a way of catching that. The
count function also worked with true and false, so I wanted to let them
through too. So I added the numbers_booleans_or_nils? method to handle
the obvious problem input.

In hindsight, it makes more sense to refactor my array_functions so that
the commands being called can handle the problem input. It’s probably
just
needs a ‘collect(:to_f)’ in front of the sum and average calls.

However, it’s the end of the day now, so the refactor will have to wait
to the morning.

Thank you again for you responses. The more I use and delve into Ruby,
the more I love it.