Feature #11689
openAdd methods allow us to get visibility from Method and UnboundMethod object.
Description
Add Method#visibility
and UnboundMethod#visibility
for getting visibility from Method and UnboundMethod object.
In GitHub https://github.com/ruby/ruby/pull/1098.
Files
Updated by hsbt (Hiroshi SHIBATA) about 9 years ago
What's use-case for these methods?
At least, You should describe use-case with feature request.
Updated by yui-knk (Kaneko Yuichiro) about 9 years ago
Sorry.
These methods are useful for inspecting Method object (e.g. debugging or documenting).
Currently if we need information about visibility, we should check owner.public_instance_methods
, owner.protected_instance_methods
, and owner.private_instance_methods
:
see also pry: https://github.com/pry/pry/blob/1f3f7e7ceff27ef516536849fc44fdf010f91c93/lib/pry/method.rb#L343
Updated by MikeVastola (Mike Vastola) about 6 years ago
Just wanted to second this FR as something I'd find useful.
Also, it would be nice to have associated predicate methods (i.e. Method#public?
, Method#protected?
and Method#private?
)
Updated by yui-knk (Kaneko Yuichiro) about 6 years ago
Thanks for your comment.
Can you show me the use cases where predicate methods are useful?
I think these predicate methods can be implemented by using #visibility
method, so these predicate methods should not be needed as core features.
Updated by MikeVastola (Mike Vastola) about 6 years ago
Oh, sorry. I missed where you were looking for an example before. Here's a good one from the popular activesupport gem: here.
As for the predicate methods, yes, they can be derrived from core methods and they -- like most core predicate methods, -- would be for convenience, but I disagree that that should be the determining factor. The same could be said for #nil?
, #is_a?
, #respond_to?
and #*_defined?
-- the functionality of which could be accomplished by checking the results of other core methods.
Updated by shevegen (Robert A. Heiler) about 6 years ago
(I think it may be easier to file a separate issue for the predicate methods,
such as Method#public?, Method#protected? or Method#private?).
Kaneko Yuichiro added the issue to the next upcoming developer meeting. Let's
see to the upcoming discussion of matz and the core developers and matz.
Updated by matz (Yukihiro Matsumoto) almost 6 years ago
The proposal sounds nice, but I am not fully satisfied with the term visibility. So how about adding public?
, private?
and protected?
methods instead?
Matz.
Updated by MikeVastola (Mike Vastola) almost 6 years ago
I mean, as seen in yui-knk's example with pry
, I think it's helpful to be able to essentially do send("#{method.visibility}_instance_methods")
. I'm not picky on the name though if there is something better than visibility.
But I think it makes sense to address any/all methods that are introduced in this issue.
Updated by mame (Yusuke Endoh) almost 6 years ago
I don't think that send("#{method.visibility}_instance_methods")
would be a frequent, strongly-recommended idiom. You can do it more explicitly as follows.
def visibility(method)
case
when method.public? then "public_instance_methods"
when method.protected? then "protected_instance_methods"
when method.private? then "private_instance_methods"
else raise "unknown method type"
end
end
This code would require work if a new visibility is introduced. But, there is no plan to add a new visibility in foreseeable future. Also, if something is actually introduced, there is no guarantee that the idiom would work as is.
Updated by Eregon (Benoit Daloze) almost 6 years ago
I think visibility is the perfect, accurate and unambiguous term for this (e.g., it's even used in the documentation of #private).
Returning the corresponding Symbol also seems very intuitive.
So take my vote as +1 for Method#visibility and -1 for 3 methods which seem very inconvenient to use.
Basically, it's 1 method versus 3 and it's strictly more expressive/powerful (the result can be displayed easily for introspection, and also compared to a known visibility).
Updated by mame (Yusuke Endoh) almost 6 years ago
FYI: The reason why matz does not like the term "visibility", is because the method attribute is not a visibility. In fact, all methods are visible in Ruby. Instead, the method attribute restricts how and where it can be called. We briefly discussed another name candidate at the meeting, but we couldn't find a good name of the concept. Then matz chose the three methods (public?, etc.) because we can avoid deciding the name.
Updated by Eregon (Benoit Daloze) almost 6 years ago
mame (Yusuke Endoh) wrote:
FYI: The reason why matz does not like the term "visibility", is because the method attribute is not a visibility. In fact, all methods are visible in Ruby. Instead, the method attribute restricts how and where it can be called. We briefly discussed another name candidate at the meeting, but we couldn't find a good name of the concept. Then matz chose the three methods (public?, etc.) because we can avoid deciding the name.
Thanks for the information :)
Right, the visibility does not affect how to call the method reflectively (which is done with Method#call), but reflects the visibility in the context of normal calls.
To be honest, I expect very few people to be confused by this.
I think it's clear it means the definition time visibility.
Metaprogramming methods in general ignore visibility (or enforce public with #public_send), so a visibility for how to call the Method object wouldn't make sense anyway.
Instead, the method attribute restricts how and where it can be called.
We briefly discussed another name candidate at the meeting, but we couldn't find a good name of the concept.
Visibility is the standard term to talk about public/protected/private and restrictions of how and where a method can be called, in all languages I know.
I think no other term makes more sense than visibility, and it is a well-known concept in programming languages.
Maybe in other natural languages this is confusing? I think in English it's as clear as it can be for an established concept.
In fact, all methods are visible in Ruby.
I'm not sure what you mean here. But one could say "method m in class A is not visible to instances of class B" and that would apply to Ruby if m is private.
Updated by duerst (Martin Dürst) almost 6 years ago
I agree that #visibility
is the best solution. When somebody mentioned this at the recent Ruby committers' meeting, I immediately thought "that's it". Benoit provides some more background.
There are arguments that this may be misunderstood, but so might the original keywords public
, protected
, and private
, and many other Ruby keywords and names. Ruby users already have to learn that private
doesn't really mean private, that in Ruby, there's always some metaprogamming workaround. Once they now it, they will apply this to #visibility
without much problems.
Updated by jacobevelyn (Jacob Evelyn) over 4 years ago
I'd also like to advocate for this. We're working on a gem that allows you to easily memoize a method while still preserving that method's visibility, and without Method#visibility
we have to awkwardly hack around it:
method_visibility = if private_method_defined?(method_name)
:private
elsif protected_method_defined?(method_name)
:protected
else
:public
end
Updated by jeremyevans0 (Jeremy Evans) about 3 years ago
I've submitted a pull request that implements @matz's idea of public?
, private?
, and protected?
: https://github.com/ruby/ruby/pull/5040
Updated by sawa (Tsuyoshi Sawada) about 3 years ago
jeremyevans0 (Jeremy Evans) wrote in #note-15:
I've submitted a pull request that implements @matz's idea of
public?
,private?
, andprotected?
: https://github.com/ruby/ruby/pull/5040
I see that there is still a comment in the pull request requesting for a single method that covers them.
mame (Yusuke Endoh) wrote in #note-11:
FYI: The reason why matz does not like the term "visibility", is because the method attribute is not a visibility. In fact, all methods are visible in Ruby. Instead, the method attribute restricts how and where it can be called. We briefly discussed another name candidate at the meeting, but we couldn't find a good name of the concept. Then matz chose the three methods (public?, etc.) because we can avoid deciding the name.
What about Method#privacy # => :private / :protected / :public
and UnboundMethod#privacy # => :private / :protected / :public
, then?
Updated by Eregon (Benoit Daloze) about 3 years ago
IMHO it'd be good to rediscuss this at a dev meeting.
It seems most people agree that Method#visibility
would be better and more convenient (also @samuel on the PR).
Potential for confusion seems extremely low (to me).
Updated by matz (Yukihiro Matsumoto) about 3 years ago
I still don't accept the term visibility
. If everyone can accept public?
, private?
and protected?
, I am OK with them.
If not, we need a new term to replace visibility
.
Matz.
Updated by Eregon (Benoit Daloze) about 3 years ago
I think #visibility
is better, but to make progress on this I'm not against adding public?/private?/protected?
instead.
It seems hard to find a new term that would fit here.
Updated by austin (Austin Ziegler) about 3 years ago
Eregon (Benoit Daloze) wrote in #note-19:
I think
#visibility
is better, but to make progress on this I'm not against addingpublic?/private?/protected?
instead.
It seems hard to find a new term that would fit here.
C++ and Java call these access specifiers
, so maybe #access
instead of #visibility
? Alternatively, a bit longer maybe #access_level
?
Updated by Dan0042 (Daniel DeLorme) about 3 years ago
Suggestions: #protection
/ #protection_level
/ #isolation
/ #isolation_level
Updated by jeremyevans0 (Jeremy Evans) about 3 years ago
I agree with @Eregon (Benoit Daloze), to make progress, it's best to merge support for public?
, private?
and protected?
. Anyone who wants to have a visibility
method can then implement it easily:
class Method
def visibility
return :public if public?
return :private if private?
:protected
end
end
Is there anyone who objects to adding public?
, private?
and protected?
? Unless there are objections, or someone comes up with a new term to replace visibility
that @matz (Yukihiro Matsumoto) accepts, I plan to merge the pull request after the next developer meeting.
Updated by jeremyevans (Jeremy Evans) almost 3 years ago
- Status changed from Open to Closed
Applied in changeset git|27278150685e738f84105d09843d3ba371146c7a.
Add {Method,UnboundMethod}#{public?,private?,protected?}
These methods allow for checking whether the method has that
visibility.
Implements [Feature #11689]
Updated by matz (Yukihiro Matsumoto) over 2 years ago
When investigating #18435, I realized the visibility of a method is not an attribute of the method. Instead, each class should have lists of methods for each visibility. Otherwise, we would face issues like #18729 and #18751. With this understanding, Method and UnboundMethod classes should not have proposed methods. Although those methods have already been shipped with 3.1, I propose to remove the methods. I estimate the impact of removing those methods is minimal.
Matz.
Updated by jeremyevans0 (Jeremy Evans) over 2 years ago
matz (Yukihiro Matsumoto) wrote in #note-24:
When investigating #18435, I realized the visibility of a method is not an attribute of the method. Instead, each class should have lists of methods for each visibility. Otherwise, we would face issues like #18729 and #18751. With this understanding, Method and UnboundMethod classes should not have proposed methods. Although those methods have already been shipped with 3.1, I propose to remove the methods. I estimate the impact of removing those methods is minimal.
I've submitted a pull request to revert this feature: https://github.com/ruby/ruby/pull/5974
Updated by Eregon (Benoit Daloze) over 2 years ago
- Related to Bug #18435: Calling `protected` on ancestor method changes result of `instance_methods(false)` added
- Related to Bug #18729: Method#owner and UnboundMethod#owner are incorrect after using Module#public/protected/private added
- Related to Bug #18751: Regression on master for Method#== when comparing public with private method added
Updated by Eregon (Benoit Daloze) over 2 years ago
- Status changed from Closed to Open
(I reopen because the new methods or equivalent functionality is not present on current master.)
Since https://github.com/ruby/ruby/pull/6242, both #18729 and #18751 are fixed.
Also "Visibility is an attribute of the method entry in a class, not an attribute of the Method object." is not a problem because now Method == method entry :)
Therefore I think we can now add {Method,UnboundMethod}#{public?,private?,protected?} again without any issue, and they will work intuitively/correctly.
@matz (Yukihiro Matsumoto) Is it OK?
Updated by Eregon (Benoit Daloze) over 2 years ago
matz (Yukihiro Matsumoto) wrote in #note-24:
Instead, each class should have lists of methods for each visibility.
I realize now you mean the existing Module#{public_instance_methods,protected_instance_methods,private_instance_methods}.
Then the functionality is technically already there but it's less convenient than what this ticket asks for and a lot less efficient.
I think we should add {Method,UnboundMethod}#{public?,private?,protected?} again.