I understand that Ruby's #initialize method is private. However, what stumps me is how Ruby makes the method private.
We normally define classes like this:
class Cat
def initialize(name)
@name = name
end
def say_name
puts @name
end
end
where #initialize
seems to be defined publicly alongside #say_name
. How does Ruby manage to make #initialize
private after the class definition?
A ruby is a pinkish red to blood-red colored gemstone, a variety of the mineral corundum (aluminium oxide). Ruby is one of the most popular traditional jewelry gems and is very durable. Other varieties of gem-quality corundum are called sapphires.
Rubies are scientifically known as corundum, a rock-forming mineral and crystalline form of aluminium oxide which is two aluminium atoms and three oxygen atoms (Al2O3) in a close packed hexagonal structure. Corundum typically contains traces of iron, titanium, vanadium and/or chromium.
Lab-created rubies are considered real because they are not much different from the natural ones. Rubies that are artificially produced are not the same as fake rubies, as they have different chemical structures from natural rubies.
Trace elements that become part of the mineral's crystal structure cause variations in its color. Chromium is the trace element that causes ruby's red, which ranges from an orangy red to a purplish red. The strength of ruby's red depends on how much chromium is present—the more chromium, the stronger the red color.
Yukihiro Matsumoto (the inventor of Ruby) has said:
#initialize is, by its design, supposed to be called only from within #new to separate per object/class initialization from the #new, thus you don't have to redefine #new. When you need/want to redefine #new, it's a sign of a bad design, I believe.
One of the reason #initialize being private is to tell you bad design.
So in summary it's a built in feature of Ruby that #initialize is automatically private and it's so developers won't easily call it outside of the .new
class method.
Very interesting question! I researched it and found some interesting things about Ruby, though I did not find the exact answer you're looking for.
initialize
is a private instance method that is meant to be redefined on most objects. It comes from BasicObject
, the Ruby class from which all objects and classes inherit.
Any new class you create in Ruby will have a private instance method called initialize
:
class Q ; end
Q.private_instance_methods.include?(:initialize)
=> true
That instance method is inherited from BasicObject#initialize
:
q = Q.new
q.method(:initialize)
=> #<Method: Q(BasicObject)#initialize>
And the method itself is not defined in Ruby, it comes from the C source of the language:
q.method(:initialize).source_location
=> nil
This is what that looks like in the Ruby source code (object.c
file):
rb_define_private_method(rb_cBasicObject, "initialize", rb_obj_dummy, 0);
rb_obj_dummy
is basically a no-op function. Which makes sense because the expectation is that you'll override initialize
with your own implementation code in your class.
All that said, your original question was about why initialize doesn't become a public method when you define it in the public space in your class definition. I don't know. Normally if you do that for any other method it will become a public method:
class Q
private
def my_private_method() "private" end
end
Q.new.my_private_method
NoMethodError: private method `my_private_method' called for #<Q:0x007fc5ea39eab0>
class Q
def my_private_method() "now i'm a public method" end
end
Q.new.my_private_method
=> "now i'm a public method"
So I guess somewhere else deep in the source code defining a method named "initialize" is handled differently from other methods. I couldn't find it, but maybe someone else can.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With