From: "David A. Black" Date: 2005-08-29T22:06:58+09:00 Subject: Re: Method behaves differently when called using #send Hi -- On Mon, 29 Aug 2005, Peter Vanbroekhoven wrote: > On Sat, 27 Aug 2005, Yukihiro Matsumoto wrote: > >> Although this explains the situation, I admit this is confusing. I >> decided to make Kernel#send to call public methods only (in 1.9 for >> the sake of compatibility). If you want to invoke private methods, >> use a new method, #fcall. > > Something has been bothering me about this still, and now I know what. > Kernel#send used to call the given method as if it was being called without > receiver (thus being able to call private methods). Changing Kernel#send does > not change how calling a method without receiver works, so the confusion > persists there. For example: > > class A > def m1(x) > "m1/1" > end > private :m1 > def method_missing(m, *args) > return "m1/2" if m == :m1 > super > end > def use_m1 > p m1(5) # prints "m1/1" > p self.m1(5) # prints "m1/2" > t = self > p t.m1(5) # prints "m1/2" > end > end > > A.new.use_m1 > > I only see two ways of avoiding this confusion. The first is not to call > method_missing for private/protected methods. In a way that makes sense > because if a method is private, it is not missing, just inaccessible. The > consequence would be that method calls with an without receiver do exactly > the same, or the one with receiver gives an error. I tend to agree that private methods are not "missing". I think that this: irb(main):008:0> class C; def x; 1; end; private :x; end => C irb(main):009:0> class C; def method_missing(m); p m; end; end => nil irb(main):010:0> C.new.x :x should give a "private method 'x'" error. Then again, that's actually a NoMethodError.... Maybe it should be a UnavailableMethodError or something. > The second possibility would be to give methods implemented through > method_missing precedence over private methods. Thus without receiver, first > a public method is sought for, if not found method_missing is called, if that > fails, the private method is called if present. So essentially it tries the > call with receiver, then it tries without. I'm not sure I follow this. If you call a method without receiver, it would call it *with* receiver first? Or do you mean "with[out] receiver" behavior would be redefined? > I think it's still OK to have two versions of Kernel#send, one that does the > call as if with receiver, one as if without receiver (which can call private > methods) -- however you name them. But the confusion is not because of > Kernel#send; it's because of the semantics of method calls with receiver vs > without receiver, and changing Kernel#send does not solve that. Well, IMHO at > least. It's also true that "send" implies "receive"... so it doesn't really mean there isn't a receiver. I think I have to let this percolate a little before I go on :-) > Or am I missing the point completely? > > Peter > > PS: fcall is used in Ruby's internals to refer to a call without receiver. > This looks like a call to a procedural function, hence fcall. It does? :-) I'm still not thrilled with fcall. It seems strange to me to introduce the concept of a "function" in Ruby just for this one purpose. David -- David A. Black dblack@wobblini.net