3

I have read that "puts" is a private instance method of the module Kernel (and therefore of Object, since Object mixes in Kernel).

That's why when we call puts, we don't specify a explicit receiver. My question is, if it's a private instance method, how is it possible that we can call it from any other scope? So, we can do:

class Test 
  puts "hello" # self is Test. So, we are calling self.puts "hello" -
end

What am I missing here? How is it possible that this works? We are calling a private instance method?

EDIT:

Same question arises if I do this:

class Object
  private
  def talk
    puts "hi there"
  end
end

class Test
  talk # outputs 'hi there'
end

Why is it possible that from class Test we can call a private method from the class Object?

Hommer Smith
  • 26,772
  • 56
  • 167
  • 296
  • Where did you read it is a private method? It is not. It is not even an instance method, as Kernel is a module, and not a class. Proof: `Kernel.puts "Proof"`. – Amadan Nov 18 '13 at 05:58
  • Because the whole Ruby program is actually happening in the context of an instance of the class `Object` (not sure, that's why I put a comment and not an answer). – Tamer Shlash Nov 18 '13 at 06:00
  • 1
    "puts and print are built-in private instance methods of Kernel—not, like the ones you write, of Object, but of Kernel. " - Rubyist 1.9 - The Well Grounded Rubyist... – Hommer Smith Nov 18 '13 at 06:00
  • Amadan, if it's a class method, why don't we need to write Kernel? http://www.ruby-doc.org/core-2.0.0/Kernel.html#method-i-puts --> It says is a public instance method – Hommer Smith Nov 18 '13 at 06:03
  • 1
    @HommerSmith - It's not a class method! It's a method of a module which is mixed into Object. – Chandranshu Nov 18 '13 at 06:06
  • Amadan, I think you should write an answer. Thank you man – Hommer Smith Nov 18 '13 at 06:07
  • Hmm. I really shouldn't - I just found out limits of my own knowledge. :) Listen to Chandranshu instead. What is true though is that it is a public method of `Kernel`, which gets included as a private method of `Object`. However, since everything inherits from `Object`, everything has access without the dot. Nothing except `Kernel` has access *with* the dot. – Amadan Nov 18 '13 at 06:11
  • 1
    Ruby's `private` is not what `private` means in other languages. The only effect is that the dot invocation (`object.method()`) syntax is disabled. Nothing else changes. If the current object inherits it, you can call it without the dot (`method()`), just like any inherited method. – Amadan Nov 18 '13 at 06:17
  • https://gist.github.com/anonymous/7523457 this doesn't let me call the method? I get an undefined error. – Hommer Smith Nov 18 '13 at 06:20
  • Looks like you have one more gist for me to explain during the time I updated my answer. – Chandranshu Nov 18 '13 at 06:34
  • @HommerSmith - Here you go: https://gist.github.com/chandranshu12/7523607 . Both "hi there" and "hi there again" are printed. Both the `talk` and `talk2` methods are private to Test and are being invoked from the Prova class definition and instantiation. Spot the difference? – Chandranshu Nov 18 '13 at 06:45
  • I see. But why in my case they behave differently? – Hommer Smith Nov 18 '13 at 06:47
  • See the updated answer. Can I have my "Accept" now? :) – Chandranshu Nov 18 '13 at 07:02

2 Answers2

3

Please have a look at the doc for the Kernel module - http://www.ruby-doc.org/core-2.0.0/Kernel.html.

Unlike Java, Ruby is not limited to Classes as containers of implementations. Modules act as wonderful containers which can be mixed into other classes. When a module is mixed into another class, all its instance methods become instance methods of those class. Since the Kernel module is mixed into the Object class, its methods are therefore available in all Ruby classes.

Please read the following:

  1. Ruby access control
  2. Common misunderstanding and clarification about access controls in Ruby

With the risk of duplication, I have to say this: private in Ruby is not the same as in C++ or Java. Subclasses of a class can call private methods declared in their superclass. In fact, you can call private method of any class using :send. The only difference between private and protected methods is that private methods can't be called with explicit receivers.

Even the last rule has an exception. If your private method is something like age=, it can (and has to be) called with self. Funny, isn't it? :)

UPDATE: (to explain the gist):

The talk method which you wrote in your code above is being called on the main object which is the context for all Ruby programs. It's not being called on the Test class which is why it's not working for your second gist.

In the gist that I have provided, talk is a private class method which is why it gets executed at the time of class definition. In the same gist, the talk2 method is an instance method and can only be called from within instance methods. Your example gist didn't work because you were trying to invoke an instance method at the time of defining the class.

Community
  • 1
  • 1
Chandranshu
  • 3,669
  • 3
  • 20
  • 37
  • I have edited my question with another example, because I think I didn't explain my doubts enough. – Hommer Smith Nov 18 '13 at 06:14
  • Please read [this](http://www.skorks.com/2010/04/ruby-access-control-are-private-and-protected-methods-only-a-guideline/) while I update the answer with more references and clarifications. – Chandranshu Nov 18 '13 at 06:18
  • Thanks for the answer, but I still don't understand what is the difference between these two: https://gist.github.com/anonymous/7523457 and https://gist.github.com/anonymous/7523614 -- One would puts the string and the other one would throw an Undefined method error. – Hommer Smith Nov 18 '13 at 06:43
  • I have replied to your comment in the question comment thread. Have a look at that gist and spot the difference. – Chandranshu Nov 18 '13 at 06:46
  • @Chandranshu: AFAIK it isn't possible to directly call a method named `age=` without using `send`. If you write `something.age=(something_else)`, that goes through the assignment operator rather than directly calling the method. (You can tell the difference because the assignment operator always returns the right operand instead of whatever the method returns.) – Chuck Nov 18 '13 at 07:05
  • @Chuck, that is not what I meant. What I mean is that you have to use `self` for such private methods. You can't call `age=` w/o a receiver. – Chandranshu Nov 18 '13 at 07:10
0

I don't understand why such long answer as in the other answer is required, or is upvoted. The answer to your question is simple.

It is because almost all classes (i.e., anything other than BasicObject) includes Kernel. Therefore, in the scope of a usual object, Kernel class is inherited, and hence its methods are accessible. That is all.

sawa
  • 165,429
  • 45
  • 277
  • 381