From: Josh Cheek Date: 2013-03-31T22:51:31+09:00 Subject: Private setters can be called by self, why not getters? --047d7b34380012023904d938cd30 Content-Type: text/plain; charset=ISO-8859-1 class Counter def initialize self.count = 0 end def increment1 self.count = count + 1 end def increment2 self.count = self.count + 1 end def increment3 self.count += 1 end private attr_accessor :count end counter = Counter.new counter.increment1 rescue $!.message # => 1 counter.increment2 rescue $!.message # => "private method `count' called for #" counter.increment3 rescue $!.message # => "private method `count' called for #" (counter.count = 0) rescue $!.message # => "private method `count=' called for #" So in Counter#increment1, we can see that we can invoke Counter#count=, even though it's private. But in increment2, we try `self.count`, which raises a NoMethodError, because we're calling a private method with an explicit receiver. But isn't that what we're doing when we say `self.count = ...` ? Somehow it works for self, but we can see in the last example that we can't do this from outside. So why can we invoke private setters with self as the explicit receiver, but not private getters? This comes up primarily because what we really want to do is increment3, but this whole time I've thought it was the setter that was causing the issue, realized last night it was the getter (b/c I was going to recommend making these protected instead of private, in order to avoid this issue). -Josh --047d7b34380012023904d938cd30 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
class Counter
=A0 def initialize
=A0 =A0 self.coun= t =3D 0
=A0 end
=A0=A0
=A0 def increment1
=A0 =A0 self.count =3D count + 1
=A0 end
=A0=A0<= /div>
=A0 def increment2
=A0 =A0 self.count =3D self.count + 1
=A0 end
=A0= =A0
=A0 def increment3
=A0 =A0 self.count +=3D 1
<= div>=A0 end
=A0=A0
=A0 private
=A0=A0
=A0 attr_accessor :count
end

counter =3D Counter.new
co= unter.increment1 =A0rescue $!.message # =3D> 1
counter.increme= nt2 =A0rescue $!.message # =3D> "private method `count' called = for #<Counter:0x007f8c998c7c60 @count=3D1>"
counter.increment3 =A0rescue $!.message # =3D> "private method= `count' called for #<Counter:0x007f8c998c7c60 @count=3D1>"<= /div>
(counter.count =3D 0) rescue $!.message # =3D> "private m= ethod `count=3D' called for #<Counter:0x007f8c998c7c60 @count=3D1>= ;"


So in Counter#increment1, we can s= ee that we can invoke Counter#count=3D, even though it's private. But i= n increment2, we try `self.count`, which raises a NoMethodError, because we= 're calling a private method with an explicit receiver. But isn't t= hat what we're doing when we say `self.count =3D ...` ? Somehow it work= s for self, but we can see in the last example that we can't do this fr= om outside.

So why can we invoke private setters with self as the e= xplicit receiver, but not private getters? This comes up primarily because = what we really want to do is increment3, but this whole time I've thoug= ht it was the setter that was causing the issue, realized last night it was= the getter (b/c I was going to recommend making these protected instead of= private, in order to avoid this issue).

-Josh
--047d7b34380012023904d938cd30--