implicit vs explicit self in private methods

D

dusty

I'm trying to understand the difference between implicitly and
explicitly calling a private method and am hoping someone could shed
some light on this for me.

class Tester
def public_hello_good
say_hello
end
def public_hello_bad
self.say_hello
end
private
def say_hello
"hello"
end
end

irb(main):001:0> require 'tester'
=> true
irb(main):002:0> a = Tester.new
=> #<Tester:0x8c294>
irb(main):003:0> a.public_hello_good
=> "hello"
irb(main):004:0> a.public_hello_bad
NoMethodError: private method `say_hello' called for #<Tester:0x8c294>
from ./tester.rb:6:in `public_hello_bad'
from (irb):4
from :0

What I'm wondering is why does this not work when I call
self.say_hello, but does work when I call say_hello? Since self is
the receiver in both cases, it seems that they would both work.

Anyone have any insight that they'd be willing to share on why it
works like that?

Thanks
 
S

Stefano Crocco

I'm trying to understand the difference between implicitly and
explicitly calling a private method and am hoping someone could shed
some light on this for me.

class Tester
def public_hello_good
say_hello
end
def public_hello_bad
self.say_hello
end
private
def say_hello
"hello"
end
end

irb(main):001:0> require 'tester'
=> true
irb(main):002:0> a = Tester.new
=> #<Tester:0x8c294>
irb(main):003:0> a.public_hello_good
=> "hello"
irb(main):004:0> a.public_hello_bad
NoMethodError: private method `say_hello' called for #<Tester:0x8c294>
from ./tester.rb:6:in `public_hello_bad'
from (irb):4
from :0

What I'm wondering is why does this not work when I call
self.say_hello, but does work when I call say_hello? Since self is
the receiver in both cases, it seems that they would both work.

Anyone have any insight that they'd be willing to share on why it
works like that?

Thanks

It's at the same time quite simple and quite confusing. It's simple because
the rule determining how a private method can be called is very short and
clear: you can only call a private method using the implicit receiver. It's
confusing because it seems natural to interpret the previous statement so that
it reads: you can only call a private method if the receiver is equal (in the
eql? sense) as the implicit receiver. However, this interpretation is wrong.
The words "only using the implicit receiver" should be taken literaly: if a
method is private, you can't call it using the dot notation
(receiver.method_name), even when the implicit and the explicit receiver are
the same thing.

I hope this helps

Stefano
 
D

David A. Black

Hi --

It's at the same time quite simple and quite confusing. It's simple because
the rule determining how a private method can be called is very short and
clear: you can only call a private method using the implicit receiver. It's
confusing because it seems natural to interpret the previous statement so that
it reads: you can only call a private method if the receiver is equal (in the
eql? sense) as the implicit receiver. However, this interpretation is wrong.
The words "only using the implicit receiver" should be taken literaly: if a
method is private, you can't call it using the dot notation
(receiver.method_name), even when the implicit and the explicit receiver are
the same thing.

Unless it ends in = :)


David
 
D

dusty

It's at the same time quite simple and quite confusing. It's simple because
the rule determining how a private method can be called is very short and
clear: you can only call a private method using the implicit receiver. It's
confusing because it seems natural to interpret the previous statement sothat
it reads: you can only call a private method if the receiver is equal (inthe
eql? sense) as the implicit receiver. However, this interpretation is wrong.
The words "only using the implicit receiver" should be taken literaly: ifa
method is private, you can't call it using the dot notation
(receiver.method_name), even when the implicit and the explicit receiver are
the same thing.

I hope this helps

Stefano

Thanks for the response.

I did find that it does work with an explicit receiver on a setter.
In the case below, I can call the private hello= method, with
self.hello=. I know that is required to state that I'm not setting a
local variable, but instead calling a method. But, it did work, so
somewhere in the code it is reading that self and understanding what I
mean by it, then perhaps dropping it and following the rules for the
rest of it?

I guess I don't really need to know why, just understand that it is
what it is. Perhaps the why is outside my scope of understanding
right now anyway. But, I am still curious.

:)

class Tester
def public_hello_good
say_hello
end
def public_hello_bad
self.say_hello
end
def public_set_hello(hello)
self.hello = hello
end
def hello
@hello
end
private
def say_hello
"hello"
end
def hello=(hello)
@hello = hello
end
end

irb(main):022:0> a = Tester.new
=> #<Tester:0x53728>
irb(main):023:0> a.public_set_hello("asdf")
=> "asdf"
irb(main):024:0> a.hello
=> "asdf"
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,981
Messages
2,570,187
Members
46,730
Latest member
AudryNolan

Latest Threads

Top