borunbabu
borunbabu

Reputation: 33

Why does 'class' show 'Class' when 'ancestors.include? Class' is 'false'?

I have a class User that inherits from ApplicationRecord. When I check User.ancestors.include?(Class), the result is false but for User.class, the result is Class.

What's the use case for the information supplied by the class method in such cases? What does it really tell me to be of practical use? It doesn't seem to have anything to do with inheritance.

Upvotes: 1

Views: 170

Answers (4)

Stefan
Stefan

Reputation: 114208

What's the use case for the information supplied by the class method in such cases? What does it really tell me to be of practical use? It doesn't seem to have anything to do with inheritance.

class works the same way for every object. Calling class on a class provides the same information as calling class on an instance. That's because in Ruby, classes are instances, too.

'foo'.class returns String because 'foo' is an instance of String. Likewise, User.class returns Class because User is an instance of Class.

In particular, User is not an instance of ApplicationRecord.

It might not be obvious that User is an instance of Class when creating it via the class keyword:

class User < ApplicationRecord; end

But it becomes very obvious when you create it explicitly via Class.new: (both examples produce the same result)

User = Class.new(ApplicationRecord)
User.class #=> Class

Because the above is just like: (using String.new for demonstration purposes)

foo = String.new('foo')
foo.class #=> String

Upvotes: 2

Moti Korets
Moti Korets

Reputation: 3748

Classes in Ruby are first-class objects—each is an instance of class Class

User is an object of class Class (which inherits from Object). class is an instance method of Object. It returns the class of the object. Therefore, User.class returns Class. Every object will have this method, and it is useful to know what the object is (e.g., for debugging). Consider this code:

1.class
# => Fixnum
"q".class
# => String

The reason why User.ancestors does not return Class is because it returns the modules included in the module. For example, Class.ancestors will include Class, but not User because User is an object of Class, which includes its own modules.

Upvotes: 1

borunbabu
borunbabu

Reputation: 33

After reading another StackOverflow post, I realized that it can only be understood by keeping the following in mind:

  1. User class has a double role. It plays Class as well as Object.
    • As Class, it lets other classes inherit from it.
    • As Object, it inherits the class method all the way up from the Object class.
  2. If I wanted my User.class to behave on the traditional lines (that is, User.class shows ApplicationRecord), then I have to override it as follows:

    class User def self.class self.superclass end end

Upvotes: 1

Cary Swoveland
Cary Swoveland

Reputation: 110725

User is a class. All classes are instances of the class Class (i.e., User.class #=> Class). Therefore, all instance methods defined on Class, or on Class's ancestors, can be invoked on User (i.e., every instance method of Class is a class method of User).

For example, one of Class's instance methods is instance_methods. One can therefore execute User.instance_methods to obtain an array of User's instance methods.

Upvotes: 2

Related Questions