Project

General

Profile

Actions

Bug #18887

closed

documentation for protected methods

Added by znz (Kazuhiro NISHIYAMA) over 1 year ago. Updated over 1 year ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:109092]

Description

I think it is correct before the change.
Which is correct?

https://github.com/ruby/ruby/commit/962a3247b1b76770930200bcce7470a54dfb25c9

Updated by jeremyevans0 (Jeremy Evans) over 1 year 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) means subclass 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.

Actions #2

Updated by jeremyevans (Jeremy Evans) over 1 year ago

  • Status changed from Open to Closed

Applied in changeset git|4813443837d76e27eb293f1928bda7a47b9e8f3f.


Fix language describing protected methods

Fixes [Bug #18887]

Actions

Also available in: Atom PDF

Like0
Like0Like0