Ramblings on Ruby Classes and Objects

Everything in Ruby is an object. Well, almost everything. At the very least, you know that if you're creating an object, you're creating an instance of the top level Object object. In fact, you can create a random object in your code like below:

some_object = Object.new

This will create an object that's an instance of the Object object. From there, things work the way you would expect. You can define attributes and methods for your some_object object.

But here is where things get interesting. The only kind of object that is capable of creating instances of itself in Ruby is a class, that is to say the only kind of object capable of calling the #new method in Ruby, is a class object. All such objects are known as classes, and are descendants of the Class class. You can declare a new class using the class keyword thus:

class SomeClass

  #class body here

end

but you can also call a class as an instantiation of Class:

some_class = Class.new

This is similar to the Object.new method you use when creating new standalone objects. By that logic, the Object object is a class, since it is capable of creating instances of itself. But we also know that classes are objects by virtue of their properties. You can send messages to classes (that is call methods on them), add methods to them, and pass them around to other objects as method arguments.

There isn't a thing you can't do with classes that you can do with objects. That's why even methods are categorized as instance methods or class methods. Instance methods are called on instances of a class (objects created by the class) while class methods are called on the class itself.


Which leads us to conclude that the Class class is, in fact, an object.So let's think through this...

Object is a class, since it can create instances of itself.

Every object you create is a descendant of Object.

Don't believe me? Let's create a class:

class some_class

  #class body goes here

end

class some_other_class < some_class       #subclass of #some_class
  
  #class body goes here

end

puts some_other_class.superclass

puts some_other_class.superclass.superclass

The output is

some_class

Object

Calling the #superclass method on some_other_class returns the ancestors of some_other_class . Calling it once returns the immediate ancestor, calling it twice returns the immediate ancestor of the immediate ancestor, and so on.

So we can see that every class in Ruby is a descendant of Object .

Therefore Object must be a class.


But we also know that every class is an instance of Class .

some_class = Class.new

So all classes are objects. Therefore Class must also be an object, right?

But if Object is a class, and Class is an object, which came first? This is the chicken-or-egg paradox.

Apparently, Ruby has a way to handle this apparent paradox. Every object in Ruby has an internal record of what class it's an instance of. The internal record of the object Class points back to Class itself. In other words, Class is an instance of itself.


So that settles it. Object is a subclass of Class, and Class is both the ultimate object and the ultimate class. It has no mother or father.

In the beginning, there was Class.

And from it, everything else flowed.

Well, not really. Class is actually a special kind of module, so it derives from Module, but that's a story for another day. 


On a meta-level, this reminds me of that age-old argument of first causes. If everything comes from something, then where does the first something come from? A lot of scientific and philosophical discussions center themselves on what the beginnings and ends of things are. Where did humans come from? Where did life come from? Where did the universe come from? Why is there something instead of nothing? Where did that something come from?


In mathematics there is a famous formulation of this problem in set theory. A set in mathematics is a collection of objects. And sets can contain other sets. So let us imagine a set that contains all the sets that ever existed. The question is, does it contain itself?

Or, if we were to rephrase this in a more fun way:Imagine a town where every man is shaved by the barber, and no man shaves himself. Who shaves the barber?


Questions of indeterminate beginnings and ends are probably the main reason why we have concepts like infinity. A line with no beginning and no end is infinite, no?


If Ruby's implementation is to be believed, it seems that such questions must accept that at some point, something will have to have no beginning, and from it everything else will flow. Something without a beginning. As counterintuitive as it sounds, it may be a viable solution.


PS: To go back to the problem of the infinite line, there is a solution to the 'line with no beginning and no end' problem that doesn't involve imagining a line that extends to the edges of the universe and beyond. That solution is the circle. It has no beginning and no end. It is its own beginning and its own end, a little like our Class object in Ruby.


PPS: The barber is a woman.

Samuel Ebeagu

Backend Engineer | Ruby on Rails Developer

4 年

Nice article man. This is a really a nice overview of the concept of object in programming.

要查看或添加评论,请登录

Ramsey Njire的更多文章

社区洞察

其他会员也浏览了