Reputation: 228
Here's an interesting case I can't seem to explain. It looks like private setters are 'kind of' private, but sometimes there are exceptions to that. Regular private methods seem to behave differently to private setters:
class TestClass
def do
self.foo = :bar # fine
self.baz # error
end
private
def foo=(other)
@foo = other
end
def baz
end
end
TestClass.new.do
The above code sets @foo
just fine, despite being called on an explicit self
. Then it fails to call #baz
, because #baz
is a private method.
What's up with this?
Upvotes: 8
Views: 297
Reputation: 369458
Private setters are special because otherwise they couldn't be called at all:
foo = :bar
Assigns to the local variable foo
, it doesn't send the message foo=
.
Note that setters aren't the only things which cannot be called without an explicit receiver. +@
, -@
, !
, ~
, []
, []=
, +
, -
, *
, /
, %
, &
, |
, ^
, **
, <<
, >>
, ==
, ===
, =~
, !~
, !=
, <
, >
, <=
, >=
, <=>
and probably some others I forgot also cannot be called without an explicit receiver. And then there's stuff like +=
, <<=
and so on.
There need to be exceptions for all of those. Unfortunately, there are only exceptions for some of those.
It has been proposed to change the rules for private
from
Can only be called without an explicit receiver, except for [this long list of exceptions which is really complicated, and still not complete].
to
Can only be called without an explicit receiver or the literal special variable
self
as receiver.
which preserves all the current properties of the definition (the most important one being that it can be determined statically at parse time).
But so far, nothing has come of it.
Upvotes: 5
Reputation: 2020
That pretty much how the private
works and it's the main difference between private
and protected
methods in ruby. You can't call private
methods on instance of the class, even inside that class, while protected
allows that.
Upvotes: 0
Reputation: 18193
If you don't use self
when using the setter method, it will instead assign the value to a local variable. More details.
In the code below, I've removed self
from the assignment to foo, and you can see the the setter is not being used b/c @foo
is nil
:
def do
foo = :bar # fine
baz # error
puts @foo # prints nil
puts foo # prints 'bar'
end
Upvotes: 1