Bug #18887
closeddocumentation for protected methods
Description
I think it is correct before the change.
Which is correct?
https://github.com/ruby/ruby/commit/962a3247b1b76770930200bcce7470a54dfb25c9
Updated by jeremyevans0 (Jeremy Evans) about 2 years ago
I don't think it is correct before or after the change, though after comes closer.
Before:
When calling a protected method the
sender must be a subclass of the receiver or the receiver must be a subclass of
the sender. Otherwise a NoMethodError will be raised.
After:
When calling a protected method the
receiver must inherit the Class or Module which defines the method. Otherwise a
NoMethodError will be raised.
The problems with the before case:
- receiver and sender may not be a class, in which case it makes no sense as stated.
- If
subclass of the (receiver|sender)
meanssubclass of the (receiver|sender)'s class
, it is still wrong.
Consider this example:
module M
protected def x; 1 end
end
c1 = Object.new
c2 = Object.new
c1.extend(M)
def c2.y(c)
c.x
end
c2.y(c1) rescue (p $!) # NoMethodError: protected method `x' called
c2.extend(M)
p c2.y(c1) # => 1
c1
and c2
are both instances of Object
. The first call to c2.y
raises because it calls c1.x
, a method defined in M
, which c1
extends but c2
does not. However, after c2
extends M
, the protected call works.
So the new language is closer. The bug in the new language is receiver
should be changed to sender
. If the receiver
didn't inherit the class or module that defined the method, you couldn't call the method on the receiver (undefined method error, or it would call a different method).
Here's another example with more traditional subclassing:
class A
def x1(b)
b.x
end
def y1(b)
b.y
end
protected def x; 0 end
protected def y; 1; end
end
class B < A
protected def x; 1; end
end
a = A.new
b = B.new
p a.x1(b) rescue (p $!) # NoMethodError: protected method `x'
p a.y1(b) rescue (p $!) # 1
p b.x1(a) rescue (p $!) # 0
p b.y1(a) rescue (p $!) # 1
This shows that a superclass instance cannot call a protected method on a subclass instance, but a subclass instance can call a protected method on a superclass instance. Superclass instance cannot call subclass protected method because superclass instance does not inherit the class/module defining the method. Subclass instance can call superclass protected method because subclass instance does inherit the class/module defining the method. This again shows the before language was incorrect, but the after language is better.
I'll switch receiver
to sender
to fix the issue in the current language.
Updated by jeremyevans (Jeremy Evans) about 2 years ago
- Status changed from Open to Closed
Applied in changeset git|4813443837d76e27eb293f1928bda7a47b9e8f3f.
Fix language describing protected methods
Fixes [Bug #18887]