Reputation: 142
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
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
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