From: Rick DeNatale Date: 2006-10-03T05:39:33+09:00 Subject: Re: Private visibility should be removed from Ruby 2 [was: Caveats with #method_missing] On 10/1/06, Tomasz Wegrzanowski wrote: > On 10/1/06, David Vallner wrote: > > On Mon, 2006-10-02 at 05:00 +0900, Tomasz Wegrzanowski wrote: > > > I have an modest proposal - can't we just get rid of private methods > > > completely in Ruby 2 ? > > > [snip justification] > > > > In my code, I use private methods for helper operations to dissect an > > algorithm into separate steps - these serve only to give fragments of > > code a name, not encapsulate any standalone functionality. Calling them > > out-of-order from client code would usually clobber an object's > > internals beyond repair. > > > > In all OO systems, the private / public distinction is to hide > > information about the inner workings of a class. While instance > > variables are obviously such information, often also how a class > > achieves what it does qualifies. > > > > If you have to call __methods__ directly, that's one more indication > > that you're Doing Something Weird. > > > > The difficulty in unit-testability is more of a failure on the side of > > the test framework. Including a "whitebox" mode in Test::Unit > > (generating public wrappers for private methods of tested classes) would > > be a more concise solution to this problem. > > > > The feature of private methods in Ruby is one I like. It's an > > encapsulation safety net as opposed to a roadblock in Ruby, but makes it > > more apparent in code that something out-of-the-ordinary is being done. > > > > I might be biased, since I'm opposed to strong usage of Ruby's > > metaprogramming capacities in "serious" code, at least without > > encapsulating such code very tightly. But removing all method-level > > encapsulation to facilitate meta hacks or get rid of some scenarios when > > they are necessary seems just overkill. > > It almost sounds that you're using Ruby as only a "better Java" :-) > Many people consider Smalltalk-style OO and metaprogramming > in Ruby extremely important. > > Back to the point. It is very unusual for OO system to have > public/private distinction. > (http://www.approximity.com/ruby/Comparison_rb_st_m_java.html) > *The* OO language Smalltalk did not have it, and other OO systems > like Objective C, CLOS, Perl 5 and Python do not have it either. Well although Smalltalk doesn't have a mechanism for identifying private methods at run-time, it's common practice to document them using categories. You see categories like 'accessing' and 'private-accessing'. Some Smalltalkers saw the lack of an enforced mechanism as a problem. I can't recall whether or not this came up in discussions in X3J20. Speaking as an experienced Smalltalker; I was the secretary of X3J20, which was the committee which developed the ANSI/ISO Smalltalk language standard; I find David's use cases for private methods far more compelling that the arguments to remove the feature. > The only listed languages that do are C++, Java and Ruby. > Conceptual model behind C++ is very far from Smalltalk-style OO. > In fact it has very little to do with OO, C++ objects are little > more than abstract data types. There is nothing remotely similar > to OO "message passing", the "methods" are merely nicely > namespaced functions with some hacks for "inheritance" (and you > need to turn inheritance support explicitly using virtual keyword, > by default you get nothing more than nicely namespaced functions). > There is no such thing as interface of an objects. The same object > is going to behave in completely different way depending on > context - a single method is going to do something completely different > depending on whether you call it from object's class, subclass of it > (and there is public and private inheritance, that changes object's > interface), or a different place. > The same method can behave differently depending on type of variable > to which object is assigned - if Foo is a subclass of Bar, then the > following code: > Foo *f = new Foo(); > Bar *b = f; > b->bar(); > f->bar(); // bar redefined in Foo, bar not virtual > can do two completely different things. All of this is true, but pretty much irrelevant as far as I can tell. > The model is already so complicated, that adding private/public > distinction to everything doesn't affect it much. Nor does it affect Ruby's model much either. > Java object model is halfway between C++ and Smalltalk. Maybe, whatever that means. Ruby does have a lot of similarities to Smalltalk, but it's quite different in other areas, including instance behavior. > Objects still do not have single clear interfaces. If Foo is > a subclass of Bar, and both have a private method bar(), > then calls to some_foo_obj->bar() will behave differently > depending on whether the call was done from methods declared in > Foo class or from methods declared in Bar class. I'm assuming that this is talking about Java. > Private methods are also *automatically final*, and therefore > they cannot be overriden. So private methods in Java still > have more to do with global functions than with regular methods. > Fortunately they at least got rid of private inheritance. Huh?!??? If I define a private method, I certainly can't call it as a global function. The lack of overriden private methods in Java is due to binding them early to methods, rather than because they are global, which they aren't. > I'm not saying "private methods" are useless in C++/Java. > They are simply not methods at all. They are nicely encapsulated > global helper functions for implementation of a class. They have > class-specific namespace and cannot be overriden, so a class > can define whatever private functions it wants to, and they do not > affect anything else. > > The only language left that has Smalltalk-style OO and this kind of > access controls in Ruby. Instead of objects having single interface > like Smalltalk or multiple interfaces like C++/Java, Ruby objects has > exactly two - one for normal method calls, and a second for "implicit self" > method calls. I can't understand what you mean here by two interfaces. The methods are in a single namespace, Making a method private affects what happens with you invoke it using an explicit receiver. > And we don't get much - defining method "private" > doesn't provide much "protection" as there is a single namespace > for all methods, so it can be accidentally redefined in a subclass. What we get is an ability to mark methods as being private at run-time. The fact that this can be overriden by subclasses is a feature which is harmonious with the basic philosophy of Ruby. > On the other hand methods cannot call private methods of different > object of the same class (or its subclasses), so objects with less-defined > interface and hidden implementation need to either hack around > access control inside own methods (ugly), or to have their internals public. I'm lost here, what does 'less-defined interface' mean? What's meant by internals? Objects internals can only be accessed by methods, Allowing methods to be private gives a tool to be used in class design. If you don't like private methods in your classes, just don't use them. > A very simple and very common example would be == method > that checks if both objects have the same class, and if so, > whether their fields are identical. This is a pretty restricted view of ==, in general the two objects don't need ot be the same class, and the comparison involves either public methods or a public conversion method. > While writing this reply I found something that really surprised me. > It is possible to get real private variables in Ruby, with private > per-class namespaces, not overridable, and working with other objects > of the same class, just like in C++/Java, by a few lines of > metaprogramming. > They are much better at encapsulation control than the official classes. Why would I want to do that, Ruby is a better Ruby than Java or C++, Java is a better Java than Ruby. C++ is the best C++, sad to say. . > > So I think it would be good idea to have method visibility controls > removed because: > * They do not fit Smalltalk-style OO, so removing them would make > everything simpler No, it would just remove a feature, and one that some Smalltalkers wished that they had. > * We get very limited benefit from them due to lack of C++/Java-style > features like per-class namespaces for private methods (or even > instance variables), and ability to call private methods of other > objects of the same type The benefit comes not from trying to do C++ style features, but from providing a mechanism to denote methods which shouldn't be called by outsiders. > * They make metaprogramming, unit testing etc. more difficult I don't see why or how. > * They provide very limited control over visibility So? At least they provide some control. > * Very simple Ruby metaprogramming gives us much more powerful private > variables anyway. Simple? > * I think it's unlikely for current visibility control system to lead > to any cool things. As far as I can tell it was never used for > implementing any magic. There is no obvious way to add any features > (even to get them to the level of that metaprogramming snippet) > without greatly complicating the language. And assuming that that's something that someone would want to do, how does having private methods get in the way? > * Ruby 2 is exactly the right time for doing such changes Well, put in a ruby change request, I doubt that it will get much support. -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/