Vaibhav Gupta
Vaibhav Gupta

Reputation: 680

Why private class methods are not allowed in ruby classes?

I came across this error while in development.

class ABC

  def self.method_1
    method_2
    p "method_1"
  end

  private

  def method_2
    p "method_2"
  end
end

ABC.method_1  # `method_1': undefined local variable or method `method_2' for ABC:Class (NameError)

But if I do it like this, then it works


  def self.method_1
    method_2
    p "method_1"
  end

  def self.method_2
    p "method_2"
  end

  private_class_method :method_2
end

ABC.method_1

Please help me in understanding this.

Upvotes: 0

Views: 54

Answers (2)

Jad
Jad

Reputation: 1286

@Jorg's answer is correct, but this might be easier to read. As Jorg pointed out, the use of the "self" applies to the class object, not the specific instance of it. basically mixing and matching the "self" and not-"self" entries is hard work, and you shouldn't try to cross the streams. the "self" and non-"self" objects will act as completely different classes.

class

class ABC
  def method_1
    method_2
    p "method_1"
  end

  def self.method_3
    method_4
    p "method_3"
  end

  private

  def method_2
    p "method_2"
  end

  def self.method_4
    p "method_4"
  end
end

output

> ABC.new.method_1
"method_2"
"method_1"
=> "method_1"

> ABC.method_3
"method_4"
"method_3"
=> "method_3"

Upvotes: 1

Jörg W Mittag
Jörg W Mittag

Reputation: 369428

In Ruby, the default implicit receiver of a message send, if you do not explicitly specify a receiver, is self.

Also, the default definee of a method definition expression, if you do not explicitly define a definee, is the closest lexically enclosing module definition.

In your first example, method1 is defined with an explicit definee of self, which at that point in the execution is the class ABC itself. This means that method1 is a class method of class ABC, which is actually just a singleton method of ABC, which in turn is just an instance method of ABC's singleton class.

method2 is defined without an explicit definee, which means it will be defined on the default definee. The closest lexically enclosing class or module definition in this case is the class definition of ABC, so method2 is defined as an instance method of ABC.

In other words: method1 and method2 are defined in two completely different classes.

Now, when you call ABC.method1, you are sending the message method1 to the explicit receiver ABC. This works, because method1 is found in ABC's singleton class.

Inside of method1, you are calling method2 without an explicit receiver. That means, the message is sent to the implicit receiver self, which is ABC in this case. So, it is roughly equivalent (module access restrictions) to ABC.method2.

BUT there is no definition of method2 in either the singleton class of ABC er the class of ABC (which is Class) or any of its superclasses (Module, Object, Kernel, BasicObject) because method2 is defined in ABC itself.

Therefore, method2 cannot be found in the method lookup chain.

In the second example, both methods are defined in the same class, namely both methods are defined in ABC's singleton class. Therefore, method2 is in the method lookup chain when called inside of method1.

In fact, your first example is actually not substantially different from this:

class Foo
  def method 1
    method2
  end
end

class Bar
  def method2; end
end

foo = Foo.new
foo.method1

Upvotes: 2

Related Questions