[ruby-core:109987] [Ruby master Bug#18729] Method#owner and UnboundMethod#owner are incorrect after using Module#public/protected/private
From:
"matz (Yukihiro Matsumoto)" <noreply@...>
Date:
2022-09-22 03:46:01 UTC
List:
ruby-core #109987
Issue #18729 has been updated by matz (Yukihiro Matsumoto).
After playing with the committed new behavior, I have noticed some points, and changed my mind (I am sorry for being late to reply).
Look at the following example:
```ruby
class C0
def foo
[:foo]
end
end
class C1<C0
def foo
super + [:bar]
end
end
m1 = C1.instance_method(:foo)
class C2<C1
private :foo
end
p C2.instance_methods(false) # (a)
m2 = C2.instance_method(:foo)
class C1
def foo
[:bar2]
end
end
m3 = C2.instance_method(:foo)
c = C2.new
p m1.bind_call(c) # (b)
p m1.owner # (c)
p m2.bind_call(c) # (d)
p m2.owner # (e)
p m3.bind_call(c) # (f)
p m3.owner # (g)
```
Before the change, the results are `a=[]; b=[:foo,:bar]; c=C1; d=[:foo,:bar]; e=C1; f=[:bar2]; g=C1`.
After the change, the results are `a=[]; b=[:foo,:bar]; c=C1; d=[:bar2]; e=C2; f=[:bar2]; g=C2`.
The problem is (a) and (d), especially the latter. As a general principle, retrieving a method object should keep the current behavior, so the expected result from (c) must be `d=[:foo,:bar]` even after redefining `foo` in `C1`. So I have to reject the idea of revealing `ZSUPER` method, along with copying.
At the same time, making owner `C2` is OK for me. But for the consistency with the idea, (a) might need to include `:foo` which is overridden in the class C2. Probably this also addresses #18435 as well.
Matz.
----------------------------------------
Bug #18729: Method#owner and UnboundMethod#owner are incorrect after using Module#public/protected/private
https://bugs.ruby-lang.org/issues/18729#change-99237
* Author: Eregon (Benoit Daloze)
* Status: Closed
* Priority: Normal
* Assignee: Eregon (Benoit Daloze)
* ruby -v: ruby 3.1.1p18 (2022-02-18 revision 53f5fc4236) [x86_64-linux]
* Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
The #owner should be "the class or module that defines the method".
Or in other words, the owner is the module which has the method table containing that method.
This generally holds, and it seems very likely this assumption is relied upon (e.g., when decorating a method, undefining it, etc).
But the returned value on CRuby is incorrect for this case:
```ruby
class A
protected def foo
:A
end
end
class B < A
p [instance_method(:foo), instance_method(:foo).owner, instance_methods(false), A.instance_methods(false)]
public :foo
p [instance_method(:foo), instance_method(:foo).owner, instance_methods(false), A.instance_methods(false)]
end
```
It gives:
```
[#<UnboundMethod: B(A)#foo() owner.rb:2>, A, [], [:foo]]
[#<UnboundMethod: B(A)#foo() owner.rb:2>, A, [:foo], [:foo]]
```
So `UnboundMethod#owner` says `A`, but clearly there is a :foo method entry in B created by `public :foo`, and that is shown through `B.instance_methods(false)`.
The expected output is:
```
[#<UnboundMethod: B(A)#foo() owner.rb:2>, A, [], [:foo]]
[#<UnboundMethod: B#foo() owner.rb:2>, B, [:foo], [:foo]]
```
--
https://bugs.ruby-lang.org/
Unsubscribe: <mailto:ruby-core-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>