Baxter
Baxter

Reputation: 142

Class::new and Class#new same thing?

The class Class has a class method version of new and an instance method version of new. But because Class is an instance of Class doesn't that make the class method version of new the instance method version of new?

When i see the following

>> Class.new
=> #<Class:0x00007fca601fe898>

I think the Class object is an instance of Class so new is an instance method of the class Class. Rather then new is a class method of the class Class.

Upvotes: 2

Views: 1431

Answers (2)

Stefan
Stefan

Reputation: 114158

Class::new and Class#new are the same.

In the sense that they actually refer to the same method. Their behavior however is very different because that method in turn calls other methods. (explained below)

Just like the new methods in other classes (String.new, Array.new etc.), Class.new resolves to Class#new. Ruby classes usually don't provide their own new class method. We can easily confirm this by replacing Class#new:

String.new #=> ""
Array.new  #=> []
Class.new  #=> #<Class:0x00007fef2517f5e0>

class Class
  def new(*args)
    "it's me, Class#new"
  end
end

String.new #=> "it's me, Class#new"
Array.new  #=> "it's me, Class#new"
Class.new  #=> "it's me, Class#new"

The original implementation of Class#new creates a new object by calling the receiver's allocate method and invoking that object's initialize method (passing arguments), something like:

class Class
  def new(*args, &block)
    obj = allocate
    obj.send(:initialize, *args, &block)
    obj
  end
end

So Class#new is a simple template method – the actual work is done by allocate and initialize. And that's where the difference comes from. By inspecting initialize we see that its owner is Class for Class#initialize but BasicObject for their instances:

Class.instance_method(:initialize).owner
#=> Class

Class.new.instance_method(:initialize).owner
#=> BasicObject

The confusion stems from the documentation which shows #initialize as ::new (which is convenient because we usually call new and rarely, if ever, invoke initialize directly). So if you open the docs for Class::new and click "toogle source" you're looking at the implementation for Class#initialize (or rb_class_initialize as it's called in C)

The only class I know that actually overrides the new class method is Struct, i.e. Struct::new:

Struct.method(:new).owner        #=> #<Class:Struct>
Struct.method(:new).super_method #=> #<Method: Class#new>

Upvotes: 1

ConorSheehan1
ConorSheehan1

Reputation: 1725

Class::new and Class#new are not the same.

Class::new Creates a new anonymous (unnamed) class with the given superclass.
Class.new Calls allocate to create a new object of class's class, then invokes that object's initialize method, passing it args.

If you click toggle source on the docs links above you can see just that.

Basically Class.new is the default initializer every other class in ruby inherits.
Class::new creates a new anonymous class.

Upvotes: 5

Related Questions