The purpose of a class is to group similar objects or objects with similar behavior together. 1 and 2 very similar, so it’s completely reasonable for them to be in the same class. true and false , however, are not alike. In fact, the whole point is that they are completely opposite to each other and have the opposite behavior. Therefore, they do not belong to the same class.
Can you give an example of what common behavior you would apply in a Boolean class? I can’t think of anything.
Let's just look at the behavior that TrueClass and FalseClass have: there are exactly four methods. No more. And in each case, these two methods do the opposite. How and why did you put this in one class?
Here you implement all these methods:
class TrueClass def &(other) other end def |(_) self end def ^(other) !other end def to_s 'true' end end
And now the other way around:
class FalseClass def &(_) self end def |(other) other end def ^(other) other end def to_s 'false' end end
Of course, in Ruby there is a lot of “magic” that happens behind the scenes, and in fact it is not handled by TrueClass and FalseClass , but rather is difficult to interpret. Things like if , && , || and ! . However, in Smalltalk, from which Ruby has borrowed a lot, including the concept of FalseClass and TrueClass , they are all implemented in the same way as methods, and you can do the same in Ruby:
class TrueClass def if yield end def ifelse(then_branch=->{}, _=nil) then_branch.() end def unless end def unlesselse(_=nil, else_branch=->{}) ifelse(else_branch, _) end def and yield end def or self end def not false end end
And again the opposite:
class FalseClass def if end def ifelse(_=nil, else_branch=->{}) else_branch.() end def unless yield end def unlesselse(unless_branch=->{}, _=nil) ifelse(_, unless_branch) end def and self end def or yield end def not true end end
A few years ago, I wrote the above just for fun, and even published it . Aside from the fact that the syntax looks different since Ruby uses special operators, while I use only methods, it behaves exactly like the built-in Ruby operators. In fact, I actually took the RubySpec conformance checking method and ported it to my syntax and it passes.