Why Ruby Doesn’t Have a Boolean Class

Why doesn’t Ruby have a Boolean class?

This is a fairly common question. Here is my answer.

Note: this is my answer, not necessarily anyone else’s. It is based on my experiences, and my understanding of things. Corrections are welcome.

First I must talk about types. And to talk about types I must talk about different languages and their type systems, and about data.

Types in C

A “value” in C essentially has two pieces of metadata: the location of some data, and the type of that data. As a gross generalisation: any piece of data in C is a sequence of bits, which said another way is just “an integer”. A given integer can be interpreted in various ways:

  • as an actual integer, with a given number of digits
  • as a memory address (at which may be stored more integers)
  • as packed data (e.g. an IEEE 754 floating point number)
  • etc.

The interpretation determines (or is determined by) which operations can be performed on the value.

The type is the piece of metadata attached to the value that describes which interpretation is correct for that particular value at that particular time.

When you write an operation in C, the compiler generates instructions to perform that operation; but the choice of instructions depends on the types of the values that are the parameters/operands and any outputs. For example, consider the instructions that could be generated to implement this simple arithmetic operation: x + 4

typeof xasmbytecode
int32_tadd eax, 483 c0 04
uint8_tadd al, 404 04
floatmov eax, 0x1234
mov dword [eax], 4
fiadd word [eax]
b8 34 12 00 00
66 c7 00 04 00
de 00

As a C programmer your job is to declare the right types for your values, and let the compiler turn your high-level operations into low-level instructions.

Casting a value to a different type lets you tell the compiler to interpret the value’s data differently, and thus generate different instructions. Casting is itself a special type of operation in that it usually only has an effect at compile-time, but some casting operations can result in run-time instructions.

Types in Java

A “value” in Java basically has two pieces of metadata, too, which at their core align with those in C: a location and a type. However in Java the data isn't just a sequence of bits – it's an object.

Generally speaking, an object is both: the location(s) of some data, and the set of operations that can be applied to or performed on that data. In Java the operations take the form of methods (which are indistinguishable from functions to all but the most hardcore of computer science nerds.)

The relationship between data and operations is maintained through the “class” hierarchy. A class is a bunch of methods, maybe some static data, and references to “ancestor” classes, which in turn have their own methods and ancestors, etc. Every object has, alongside its concrete data, a reference to its class.

When a method is invoked on a value/object, the compiler uses the value’s type metadata and underlying object's class reference to find the nearest ancestor that defines the method in question, and generates instructions to invoke that particular method with the object's data.

To facilitate this process, Java is incredibly anally retentive about ensuring that every value’s type corresponds with its object’s class, or a superclass thereof.

This example from Stack Overflow is really nice, so I’ve changed it:

interface Domestic {}
class Animal {}
class Dog extends Animal implements Domestic {}
class Cat extends Animal implements Domestic {}

Animal pet = new Dog();

pet instanceof Domestic // true - Dog implements Domestic
pet instanceof Animal   // true - Dog extends Animal
pet instanceof Dog      // true - Dog is Dog
pet instanceof Object   // true - Object is the superclass of all

The type of the variable pet is Animal, and the actual object’s class is Dog, which has Domestic, Animal, and Object as superclasses.

The type and class are intrinsically linked, and introspective operators like instanceof, as well as Java’s strict compile-time type enforcing, raise this duality to the fore.

As a Java programmer your job is to define your class’s methods, and invoke methods on values based on their types.

Types in Ruby

Like Java, Ruby is an object-oriented language; however the type system works a bit differently from C or Java. For the purposes of symmetry let’s say that a “value” in Ruby has a location and a type; however for the purposes of illustration let’s say that all values in Ruby have the same type, i.e. they are all “Ruby objects”.

Because the type is always the same there is no need for a compiler to inspect that metadata and work out which instructions to generate to invoke a method. Instead all method invocations use the same instructions, which means they take effect at run-time; following the object’s class reference, traversing the ancestry hierarchy, and dispatching the method.

In turn this allows Ruby programs to redefine methods and classes and ancestry on the fly. Ruby is a dynamic language.

This means that the class of an object in a Ruby program is not its type, in the usual sense; rather it is just a collection of functionality (methods) that apply to it. Common method implementations go into a common ancestor class.

Further along this train of thought, Ruby espouses a paradigm known as “duck typing” – which is to say that an object that waddles like a duck and quacks like a duck is, in fact, a duck. To compare it to our Java example above, the Dog class wouldn't have to extend the Animal class to be considered an animal, it would only have to implement the methods that are common to animals – eat, breathe, sleep, etc. Ditto the Domestic interface.

And so to the question: Why doesn’t Ruby have a Boolean class?

The true and false objects in Ruby don't share any common method implementations. In fact, they’re the least likely pairing of objects to do so, since they are exact opposites. They may share similar interfaces (the set of method names, parameter lists, semantics, etc.) but the implementations will always be different.

If Dog and Fish don't share any common implementation there's no need for an Animal class, even if they can both eat and breathe. They do them all differently.

And that is why Ruby does not have a Boolean class.



thumbnail image

Matthew Kerwin

Published
Modified
License
CC BY-SA 4.0
Tags
development, ruby, software
Why doesn’t Ruby have a Boolean class? This is a fairly common question. Here is my answer. Note: this is my answer, not necessarily anyone else’s. It is based on my experiences, and my understanding of things.

Comments powered by Disqus