From: "jeremyevans0 (Jeremy Evans)" Date: 2022-07-14T20:27:55+00:00 Subject: [ruby-core:109212] [Ruby master Bug#18887] documentation for protected methods Issue #18887 has been updated by jeremyevans0 (Jeremy Evans). 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)` means `subclass of the (receiver|sender)'s class`, it is still wrong. Consider this example: ```ruby 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: ```ruby 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. ---------------------------------------- Bug #18887: documentation for protected methods https://bugs.ruby-lang.org/issues/18887#change-98347 * Author: znz (Kazuhiro NISHIYAMA) * Status: Open * Priority: Normal * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN ---------------------------------------- I think it is correct before the change. Which is correct? https://github.com/ruby/ruby/commit/962a3247b1b76770930200bcce7470a54dfb25c9 -- https://bugs.ruby-lang.org/ Unsubscribe: