Warning: The following is pretty long but it has an interesting surprise ending. At least it surprised me and I even think David will find it quite satisfying (and maybe even Matz). On Jan 23, 2007, at 12:54 PM, dblack / wobblini.net wrote: > I've come to think that: > > m = a.method(:x) > m.call > > does not involve a receiving the message "x", in any useful sense of > the term "receiving". So I don't think it's just a matter of avoiding > "future" in a case where something will happen in the future; rather, > it's a different scenario from a.x. It's avoiding "receiver" in a > case where the object in question is not the receiver of the message > in question. > > But I'm in a tiny minority on every phase and nuance of this, so > that's probably that :-) I have no way of knowing who is in the minority on this issue but I very much agree with Robert Dober's sentiments: "... I feel that the argument teaches me a lot". The only reason that I keep tugging at this thread is that David had thrown into doubt my assumption that every method in Ruby executes within the context of a 'receiving' object which is syntactically identified by 'self'. I've generally found David's thinking on the more dusty corners of Ruby semantics to be very illuminating so his suggestion that the concept of 'receiver' didn't apply with respect to instances of Method came out of left field for me. I wonder if we can brake the logjam a bit by thinking about the situation in a different way. Given: class A def x(b,c); self; end end obj = A.new consider the following snippets of code: obj.x(1,2) # 1 obj.foo_then_bar(:x, 1, 2) # 2 obj.foo(:x).bar(1,2) # 3 Case 1 is just the normal method invocation. Case 2 is a way to name the method via an expression but is otherwise the same as case 1. The name 'foo_then_bar' hints that this is a two step process. Case 3 explicitly breaks up case 2 into two distinct steps. Lets look at the same code with some different terminology: obj.x(1,2) # 1 obj.resolve_then_apply(:x, 1, 2) # 2 obj.resolve(:x).apply(1,2) # 3 I've tried to pick names that suggest appropriate semantics without dragging in the controversial semantics we've been talking about. This suggests that: f = obj.resolve(:x) must return an object that encapsulates a reference to obj and also encapsulates a reference to the definition of A#x found by 'resolving' :x relative to obj. This object must also respond to 'apply' such that f.apply(1,2) causes A#x to be called with the arguments 1 and 2. Of course I hope everyone who is still reading has figured out that obj.resolve_then_apply(:x, 1, 2) is just our old friend 'send': obj.send(:x, 1, 2) And within this context we've been happily saying things like: The message :x is sent to obj. obj is the receiver of the message :x When A#m executes, 'self' points to obj. When A#m executes, obj is the implicit receiver. obj receives message :x, searches for a matching method, and then executes the method with arguments 1 and 2. As long as 'send' is viewed on the outside as a complete process the send/receive terminology works quite fine. But... ... if we think of the process not as 'send' but instead as 'resolve_then_apply(:x, 1,2)' or 'resolve(:x).apply(1,2)' then the send/receive metaphor starts to fall apart. It wasn't until I finally wrote all this out that I really started to understand what David was getting at. When I started writing this post I didn't expect to end up at this point. I believe David has been suggesting all along that if we hit the pause button just after the 'resolution' process has finished but before the 'apply' process has started, then at that moment it can be said that 'obj' has received :x, i.e. there is no more 'receiving' to be done, that part of the process is done, finito, fait accompli. All that is left is the 'apply' process. Going back to the code: f = obj.resolve(:x) # 1 f.apply(1,2) # 2 During step 1, obj receives message :x and resolves the message into a method definition which is captured and returned within f. During step 2, the arguments 1 and 2 are applied to obj using the method definition that was previously resolved. If we switch the example back to the standard names we get: m = obj.method(:x) # m is an instance of Method m.call(1,2) So to bring this back full circle. David pointed out that m.receiver # obj was 'anomolous' because m (an instance of Method) is all about the 'apply' step of the process and *not* about the 'resolve' step of the process. In the 'resolve' step, obj is the receiver of the message but that step is water under the bridge once you've constructed an instance of Method. And here is the real problem: We don't have any accepted terminology for the role of obj during the 'apply' process. We never needed any because Method doesn't have an accessor for that data. It never needed to be named. And then Wolfgang posted his message with the innocuous sounding title of "Minor Change Proposal for Classes 'Object' and 'Method'." Matz pointed out that all along it has been quite common to refer to the object associated with 'self' as the implict or default receiver. So why not use Method#receiver? It made sense to me. The gotcha is that in: def m1(a,b) m2 end self is the implicit receiver of the message :m2 but we can't really say anything at all about self with respect to :m1 because the question just isn't meaningful from the perspective of the execution of m1. It is only a meaningful question from the perspective of how m1 came to be executed. obj.m1(1,2) # obj is the receiver or m = obj.method(:m1) # obj receives and resolves :m1 here m.call(1,2) # the empty argument list is applied # to obj and the resolved method I know I'm probably splitting hairs at this point but that is exactly what Kernel#method does and I *think* it is exactly what David was pointing out. Here is yet another way to illustrate this hair splitting that makes it blindingly obvious (to me at least) what David was getting at: a = [1,2] b = [3,4] fa = a.method(:first) uf = fa.unbind fb = uf.bind(b) fb.call # 3 Question: Where in this example does b receive the message :first? Answer: Nowhere, because b is never the receiver of the message :first. I'm hoping that David is jumping up and down now saying I told you so! Taking all this into consideration, I think that Vincent Fourmond's suggestion of Method#target is a pretty good one. The object captured within an instance of Method is the 'target' of the 'apply' process I described above. It also suggests that when talking about 'self' within an instance method we might use terminology such as: self is the target of the method and is the receiver of any unqualified messages I also realized that there are circumstances where 'self' is not the target of any method at all but is still a receiver of messages: class X attr :foo end Within a class block, self is the implicit or default receiver of messages but is not the 'target' of any particular method. Gary Wright