From: David Vallner Date: 2006-10-02T09:15:17+09:00 Subject: Re: Private visibility should be removed from Ruby 2 [was: Caveats with #method_missing] --------------enigDE69D55A9FC815C6156E431A Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Tomasz Wegrzanowski wrote: > 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. >=20 Maybe. > 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. >=20 > The only listed languages that do are C++, Java and Ruby. > They forget Ada, Simula 87, Eiffel... > Conceptual model behind C++ is very far from Smalltalk-style OO. Smalltalk-style OO isn't the only true one. In fact, object-oriented programming is known to have no actual definition. > There is nothing remotely similar > to OO "message passing",=20 See above, OO !=3D message passing. And even in Smalltalk, the message pass will trigger a method invocation most of the time. > 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). That's a specific C++ quirk that comes is part historical, part intentional. A design policy of C++ is that it should introduce no overhead over C unless explicitly stated by the programmer. Vtable method dispatch is overhead, that's why it has to be explicitly enabled. > There is no such thing as interface of an objects. Pure virtual classes. > 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 =3D new Foo(); > Bar *b =3D f; > b->bar(); > f->bar(); // bar redefined in Foo, bar not virtual > can do two completely different things. > The model is already so complicated, that adding private/public > distinction to everything doesn't affect it much. >=20 Once again, C++ quirks which do have a reason, even if you might find them unjustified. Also are completely unrelated to the issue of access level restriction, except as an "Oh, look, this thing about C++ sucks, that's why another thing that's in C++ too sucks." > Java object model is halfway between C++ and Smalltalk. > Objects still do not have single clear interfaces. Can you elaborate on what you expect as a clear interface? > 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. That's why you use protected on methods you intend to be called in subclasses. > 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. That's why you use protected on methods you intend to be overridden in subclasses. > Fortunately they at least got rid of private inheritance. >=20 Eiffelists might disagree. Multiple inheritance, private inheritance, and feature renaming are core features of Eiffel's object model as far as I know. > 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. The question is what distinguishes a method from a function. Is it the polymorphic dispatch, or being bound to a specific object? In CLOS, it's only the former because of multimethods, in other languages polymorphic dispatch seems to happen as a consequence of the latter. Once again, lacking an actual definition of object-orientation, both approaches can be considered equally valid. > 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. >=20 I consider uncontrolled namespace clobbering such as this a flaw of ruby. "Module Foo does weird stuff to module Bar because the author of Foo thought they're convenient / more Right (tm) and now my code broke when I wanted to add support for Foo." Bugs like that are annoying in the least. > 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 s= elf" > method calls. I personally think this is a design burp. > 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. Separating private methods in a separate namespace has been thought for Ruby 2.0. No idea what happened to the proposal. > On the other hand methods cannot call private methods of different > object of the same class (or its subclasses), so objects with less-defi= ned > interface and hidden implementation need to either hack around > access control inside own methods (ugly), or to have their internals > public. Protected. I don't like calling private methods on other objects in Java either and find it one of the C++ quirks that shouldn't have made it into that language. > A very simple and very common example would be =3D=3D method > that checks if both objects have the same class, and if so, > whether their fields are identical. >=20 If an operation can't be implemented only communicating with another object's public interface, there's something wrong with the design. You may differ on this point, I'll admit it's one of taste more than anything else. > [snip metaprogramming code] >=20 > 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 Ruby isn't Smalltalk. > * 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 I argue that it would be better to just fix those design burps instead of removing a language feature. > * They make metaprogramming, unit testing etc. more difficult More verbose. Not really difficult - at least for metaprogramming you need a miner helmet for when you need to bang your head against a wall anyway. > * They provide very limited control over visibility I can't imagine it could be improved without making them not the advisory "you shouldn't do this" tags they are now. > * Very simple Ruby metaprogramming gives us much more powerful private > variables anyway. Remove a core language feature only to get umpty modules reemulating it in incompatible ways? > * 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. It's used to tighten up code, make possible bugs due to metaprogramming more visible, etc. Not necessarily cool or magical. Mind you, cool and magical aren't necessarily good qualities. > * Ruby 2 is exactly the right time for doing such changes >=20 The Ruby 1 -> Ruby 2 transition isn't supposed to be in the order of the Perl 5 -> Perl 6 one. As far as I know, the changes are mostly touchups that fall out of scope for a minor version bump because they address some of the core design burps. As far as I know, it's supposed to be as little codebreaking a change as necessary. Ruby 2 is not at all the time for a keyword removal and object model revamp. David Vallner --------------enigDE69D55A9FC815C6156E431A Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.5 (MingW32) iD8DBQFFIFoPy6MhrS8astoRAuhGAJ0Q6BEksykY2bBXnMjO3Hd+9wbxBwCfd50Q PQNhHtXjT/lv2MO/uQ09zqM= =VLso -----END PGP SIGNATURE----- --------------enigDE69D55A9FC815C6156E431A--