Ruby Craziness: Class VS Object

Ruby craziness: Class vs Object?

Basically the key thing to understand is that every class is an instance of the Class class and every class is a subclass of Object (in 1.8 - in 1.9 every class is a subclass of BasicObject). So every class is an object in the sense that it is an instance of a subclass of Object, i.e. Class.

Of course this means that Class is an instance of itself. If that makes your brain hurt, just don't think about it too deeply.

Object and Class are is_a? Object

x.is_a? y returns true if x.class == y or x.class < y, i.e. if x's class is y or x's class inherits from y. Since every class inherits from object x.is_a? Object returns true no matter what x is. (In 1.8 anyway, in 1.9 there's also BasicObject which is now the most basic class in the inheritance hierarchy).

They are also is_a? Class

Both Object and Class are indeed classes, so that should not be surprising.

They are also instance_of? Class, but not instance_of? Object.

Unlike is_a?, x.instance_of? y only returns true if x.class == y, not if x.class is a subclass of y. So since both x and y are instance_of? Class, they're not instance_of? Object.

right, nothing can be instance of object.

That's not true. Object.new.instance_of? Object is true.

kind_of?

kind_of? is an alias for is_a?, so see above.

So both are exactly same, then why do we have both these.?

It should be pointed out that everything up to now is true for all classes. E.g. String.is_a? Object, String.is_a? Class and String.instance_of? Class are true and String.instance_of? Object is false for the same reasons as above. (Also String.is_a? String and String.instance_of? String are both false for the same reasons - String is a class, not a string).

You can not conclude from this that all the classes are the same. They're just all instances of the same class.

Comparing methods

Since both Object and Class are classes, they both have all the instance methods defined by Class. Class additionally has the singleton method nesting. nesting tells you which module you're currently nested in, it has nothing to do with inheritance.

For any given class TheClass.methods will return the instance methods defined by Class (e.g. superclass, which returns the class which TheClass inherits from, and new which creates a new instance of TheClass) plus the singleton methods defined by that class.

Anyway methods only tells you which methods can be called directly on a given object. It does not tell you which methods can be called on an instance of a class. For that you can use instance_methods, which returns significantly different results for Object and Class.

Ruby's Classes and Objects

You have several things wrong.

  • (2.) The reason Class, Module, Object, and Basic Object are instances of Class is not because Class < Module < Object < BasicObject. It has nothing to do with it.
  • (3.) (Object.new).instance_of? Class returns false not because Object.new is an instance of Object. It is because it is not an instance of Class.
  • Class.is_a? Object is true not because [the mentioned] Class is a subclass of Object. It is because (the mentioned) Class is an instance of Class (which is not mentioned), which is a subclass of Object.

The answer to the question is: Object.is_a? Class returns true because Object is an instance of Class.

If you want to know the class of an instance, use instance_of? or class methods.

3.is_a?(Object) # => false
3.is_a?(Fixnum) # => true
3.class # => Fixnum

The Class/Object Paradox confusion

You can see the problem in this diagram:

Ruby Method Lookup Flow

(source: phrogz.net)

All object instances inherit from Object. All classes are objects, and Class is a class, therefore Class is an object. However, object instances inherit from their class, and Object is an instance of the Class class, therefore Object itself gets methods from Class.

As you can see in the diagram, however, there isn't a circular lookup loop, because there are two different inheritance 'parts' to every class: the instance methods and the 'class' methods. In the end, the lookup path is sane.

N.B.: This diagram reflects Ruby 1.8, and thus does not include the core BasicObject class introduced in Ruby 1.9.

ruby class and object - different methods of comparison

You are right == and === are different methods on the String class and an instance of String. Have a look at the different documentation for

  • Module.==
  • Module.===
  • String#==
  • String#===

Why String == String evaluates to true but String === String does not?

As you can see in the docs Module.== basically means if both sides are the same Object. Is the String class the same as the String class? Yes. But Module.=== returns true if the right side is an instance of the class on the left. Id String an instance of String? No.

Why s1 === String is false but String === s1 is true?

s1 === String calls === on an instance of string. This method returns true when both sides are the same object. Are an instance of String and the class Sting the same object? No. But String === s1 has – as already explained before the meaning of is_a?: Is an instance of String an instance of String? Yes.

Why do methods inside a class become instance methods instead of becoming singleton methods of the class itself?

It works similarly to message sends and constant lookup:

  • The general format of a message send is foo.bar, which sends the message bar to foo. If you leave out foo, the message will be sent to the default receiver (which is self).
  • The general format of a constant lookup is Foo::Bar, which looks up the constant Bar in the module Foo. If you leave out Foo, the constant will be looked up in the default constant context (or cref).
  • The general format of a method definition is def foo.bar, which defines the method bar in the singleton class of foo. If you leave out foo, the method will be defined in the default definition context (or default definee):

    • At the top-level, the default definee is Object. (Also, the methods become private.)
    • Within a module declaration body, the default definee is self (and not self's singleton class, like you assumed!)
    • Within a method body, the default definee is the syntactically enclosing module. (Put another way: def doesn't change the default definee.)
    • instance_eval changes the default definee to the receiver's singleton class
    • class_eval changes the default definee to the receiver


Related Topics



Leave a reply



Submit