From: Meinrad Recheis Date: 2007-06-14T05:36:46+09:00 Subject: Re: new method dispatch rule (matz' proposal) On 6/13/07, David Flanagan wrote: > This is a late response to the very long thread that started back in > January with this message: > > http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/9996 > > As I understand it, the problem Matz is seeking to address is that > private methods are inherited by and may be overridden by subclasses. > This means that a subclass writer can inadvertently alter the behavior > of its superclass simply by defining a method that has the same name as > an internal helper method of the superclass. The only way to defend > against this is for subclass writers to be familiar with the internal > implementation of the superclass. > > Matz's proposal was to resolve this problem by altering the method > resolution algorithm. If I understand correctly, the problems were: > > 1) It was kind of complicated > 2) The method lookup algorithm depended on whether a method was called > functionally without an object prefix or in OO form with an object > prefix. (That is called as foo() or o.foo()) > 3) There were backward compatibility issues > > Part of the discussion was about the question of whether to alter the > semantics of private methods, or add a new "local" or "personal" > visibility level for methods that were truely local to the defining > class and could not be inherited or overridden. > > With all that as review, here are my thoughts on the matter. > > 1) It is reasonable to expect private methods (or local methods if we > call them that) to be looked up and dispatched differently than > non-private methods. > > 2) The problem, though, is that since Ruby is a dynamic language, the > interpreter can't tell whether a method is private or not until it has > looked it up. > > 3) Therefore, solutions like Matz's proposal depend on the method > invocation syntax (functional style versus object-oriented style) to > determine which method lookup algorithm is to be used. This leads to > the confusing and hard-to-justify situation in which the invocation > "foo" might do something different than the invocation "self.foo". > > I propose, therefore, that some new syntax be introduced (avoiding > backward incompatibility) either for making local method names obviously > different from other method names. Or that a new method invocation > syntax be introduced and that this new syntax be used when we want to > invoke a local method defined in (or inherited by) the caller without > considering any methods defined further down the class hierarchy. > > I don't grok parse.y well enough to know whether any syntax I would > propose would actually result in an unambiguous grammar, but my > suggestion is that local methods have an @ prefix just like instance > variables do. Then the interpreter knows from the name of the method > that it is to be dispatched differently. > > In fact, I might actually go further than this and propose that local > methods are not actually methods, but are syntactic sugar for lambdas. > > In Ruby 1.8, we can write code like this: > > class Test > def initialize(greeting) > @greeting = greeting > @greeter = lambda { |x| puts "#@greeting #{x}" } > end > > def greet(x) > @greeter[x] > end > end > > t = Test.new("hello") > t.greet("world") > > In this code, the instance variable @greeter refers to a local function > that is completely hidden from subclasses and cannot be altered. I strongly disagree here. While I think it is good to protect private methods against inadvertently overriding them, I consider it harmful to completely hide them from subclasses. If I really want to change something I should be able to do so (i.e. via reflection). In languages with strict privacy concepts like Java it is a pain to extend a class in ways other than intended by the author of that class. -- henon > > Perhaps Ruby 1.9 could take this idiom and add syntax sugar to make the > definition and invocation of local functions more like the definition > and invocation of regular methods. > > David Flanagan > >