This is the old RCRchive. It's available only for reading and reference. To submit RCRs for Ruby 1.9/2.0, and to participate in discussions about them, please visit the new RCRchive.
ruby picture

RCR 349: Complete removal of "protected" visibility from Ruby

Submitted by Tomasz Wegrzanowski (Fri Oct 06 21:21:14 UTC 2006)

Abstract

"protected" visibility is very rarely used, very difficult to understand, impossible to retrospect and correctly metaprogram without major changes in the the language, and doesn't fit with other parts of Ruby. The best course of action is to remove it completely.

Problem

Method with "protected" visibility can be called if class of self is the same class or a subclass of a class in which given method was defined.

This definition is very problematic. Nowhere else in the language a concept like "a class in which given method was defined" occurs - methods are normally associated with objects, and for all other operations it doesn't matter in what way they were defined.

Likewise, concept like "class of self in caller" doesn't occur anywhere else in Ruby. self is simply some object, so its class should not matter. Caller self isn't even directly involved here, as protected visibility is relevant only for "explicit receiver" method calls.

Protected visibility cannot be currently reflected about, as there is no way to ask an object in which classes where its methods defined - if Foo has protected method #xyzzy, and Bar < Foo has protected #xyzzy, we have no way of learning whether Bar#xyzzy is simply Foo#xyzzy (and can be called from within instance of Foo), or redefined Bar#xyzzy (and can only be called from within instance of Bar).

Protected method calls cannot be delegated. To delegate we first need information on caller's context, that is at least self in the caller. Then self.instance_eval { obj.protected_send(...) } could work. Concept of "self in the caller" is found nowhere else in Ruby.

Even if full set of operations needed to support "protected" was provided, metaprogramming would be significantly more difficult. In practice delegation and other metaprogramming is most likely to disregard correct handling of "protected" visibility, and those few programs that use "protected" are likely to encounter bugs.

Proposal

Completely remove protected visibility.

Remove protected, protected_methods, protected_instance_methods, protected_method_defined? methods from Module class, and anywhere else it is present.

Analysis

"protected" does not work well with the rest of Ruby. There are three alternatives. It can be removed completely (as this RCR proposes), full support for it can be added, or it can be left as is.

Cost of full support would be significant. Concepts like "class where method was defined" and "class of self in caller" would have to be supported thoughout the language, third version of "send" would be required (in addition to private funcall and public send), and metaprogramming would become significantly more complex to support "protected" correctly.

"protected" is defined in terms of relation between two classes (class of self in caller and class where method was defined), neither of which is a class of the object in question. Such visibility makes sense in class-centric style of programming (like Java or C++), and adequate support for it would necessarily change currently very object-centric Ruby into a more class-centric language.

If "protected" was widely used and was considered highly valuable, these changed could have been worthwhile. In reality, protected is rarely used, and when it is, it usually has small utility and can be easily replaced by other constructs like asking objects about their types. Significantly changing the language only to keep "protected" doesn't seem to be a good trade-off.

Keeping current situation of having "protected" visibility in Ruby without adequate support from rest of the language would ensure full backwards-compatibility, however programs that use protected would behave inconsistently when used together with many solutions based on metaprogramming, so "protected", even if kept, would most likely stay virtually unused.

Because protected is used very rarely, backwards compatibility would be broken for very few programs. Because of the minor backwards incompatibility, it's best to remove "protected" when moving to Ruby 2.

Implementation

Patch against today's 1.9 CVS is at http://zabor.org/taw/removal_of_protected.diff.gz

I haven't tested it, but it looks like it works, and make test returns "test succeeded".

ruby picture
Comments Current voting
Your analysis contains valuable insight. Let me consider it for a while.

Proper message delegation functionality might solve the problems at least in part. Maybe the one with "private" visibility as well.

-matz.


It found out that Rails uses protected extensively. So, your assumption that "protected is rarely used" is not true. Even though it could be replaced by other features (or visibilities), we have to address that anyhow.

-matz.


Strongly opposed0
Opposed1
Neutral0
In favor2
Strongly advocate1
ruby picture
ruby picture

Powered by Ruby on Rails.