9

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?

3
  • Surely that's just how OOP works? Commented Mar 31, 2015 at 15:54
  • What's being asked is why the initialize method is special. It hasn't been declared as private. Commented Mar 31, 2015 at 16:10
  • Yup, exactly what tadman said! Commented Apr 1, 2015 at 13:25

2 Answers 2

10

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, but I was wondering how is #initialize made private after we define it. When we finish the class definition, is there something happening in the background that privatizes #initialize, even though we've defined it publicly? Or is it just some magic that happens in C land?
It's Ruby. #initialize is a special keyword to Ruby and when it encounters it, it will ensure it's considered private.
7

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.