Private and protected

Could anybody explain me this, please?

class First
def say
self.phrase
end

 private

 def phrase
     'something'
 end

end

a = First.new
a.say

got

NoMethodError: private method b' called for #<A:0xb7756518> from (irb):44:insay’
from (irb):52
from :0

If i write the same code with ‘protected’ instead of ‘private’ I got no
error.
If i write the same code with calling ‘phrase’ instead of ‘self.phrase’
in ‘say’ method I got no error again.

The call ‘self.phrase’ is a call to a class method but ‘def phrase’ is
the definition of an instance method. Either remove the self in the
say method or change ‘def phrase’ to ‘def self.phrase’.

It has nothing to do with private or protected.

On Wed, Nov 23, 2011 at 10:20:54PM +0900, Николай wrote:

    'something'

If i write the same code with ‘protected’ instead of ‘private’ I got no
error.
If i write the same code with calling ‘phrase’ instead of ‘self.phrase’
in ‘say’ method I got no error again.

A private method may only be called with an implicit receiver - in
self.phrase, self is explicit, which is why you get the exception. The
practical upshot of this is that private methods may only be called by
the
current instance, because the implicit receiver is understood to be
“self”.

Protected methods may be called by the current instance, instances of
its
class or instances of it subclasses, and require an explicit receiver,
except when the receiver is the current instance. I would tend, even
then,
to pass it explicitly to help make the code’s intent clearer.

This has been expressed much more elegantly in numerous places, so
search
the web if I only served to confuse!

Dan

On Wed, Nov 23, 2011 at 14:08, Peter H.
<[email protected]

wrote:

The call ‘self.phrase’ is a call to a class method but ‘def phrase’ is
the definition of an instance method. Either remove the self in the
say method or change ‘def phrase’ to ‘def self.phrase’.

It has nothing to do with private or protected.

This isn’t correct, it has everything to do with private or protected!
The
methods and method calls in the example are all instance methods, not
class
methods. self.class.phrase would be a class method call.

As Daniel has said, the “problem” is that private methods may not be
called
with an explicit receiver.

Although, a common workaround if you really need to send an object a
private method (message) is to do it with the Object#send method. So you
could do:

self.send(:phrase), but then again it would be completely useless in
this case because you could do without the receiver altogether.

There’s also an Object#pubic_send(:method, *args, &blk) that just works
for public methods.

-Luke

I stand corrected.

On Wed, Nov 23, 2011 at 3:08 PM, Peter H.
[email protected] wrote:

The call ‘self.phrase’ is a call to a class method

I am sorry, this is wrong. A class method would be called with
“self.class.phrase”. “self.phrase” attempts to invoke an instance
method.

but ‘def phrase’ is
the definition of an instance method. Either remove the self in the
say method or change ‘def phrase’ to ‘def self.phrase’.

It has nothing to do with private or protected.

It has:

irb(main):001:0> class First
irb(main):002:1> def say_1; self.phrase; end
irb(main):003:1> def say_2; phrase; end
irb(main):004:1> private
irb(main):005:1> def phrase;“ph”;end
irb(main):006:1> end
=> nil
irb(main):007:0> f = First.new
=> #First:0x10183174
irb(main):008:0> f.say_1
NoMethodError: private method phrase' called for #<First:0x10183174> from (irb):2:in say_1’
from (irb):8
from /opt/bin/irb19:12:in `’
irb(main):009:0> f.say_2
=> “ph”

See Daniel’s explanation.

Kind regards

robert