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