views:

209

answers:

3

In the example below, why do we say "k.send :hello" instead of "k.receive :hello" if, as stated elsewhere, k is actually the receiver?

It sounds like k is the sender rather than the receiver.

When we say "k.send :hello" who is sending, if not k?

(Are you as confused as I am?)

class Klass
  def hello
    "Hello!"
  end
end
k = Klass.new
k.send :hello   #=> "Hello"
k.hello         #=> "Hello"
+6  A: 

In Smalltalk, everything is an object. The "sender" is the object who is the owner of the scope where the message originated (i.e. the "this" or "self" pointer).

As before, Ruby inherits this concept. In less abstract terms, if I post you a letter, I am the "sender" (it came from my office), and you are the "reciever" (the address on the front is yours). So I'd write foo.send myLetter: You, foo, receive my letter. The sender is implicit, the owner of the code doing the "posting".

Adam Wright
Hmmm. Still really confused about this. I'm coming from Java. So I "call" a method on an object. Is that different from this send/receive notion or just different terminology?
lorz
It's just different terminology: For "call", read "send message". For "I've been called", read "I am the receiver"
Adam Wright
It's not just different terminology. You can send messages that have no corresponding method. You can't call a method that doesn't exist.
Chuck
Chunk: That depends on the implementations. True, in Smalltalk you can message things that don't exist. In Objective-C, this is a runtime failure. In C++, you can't call methods that don't exist. In Ruby, again, it's a runtime failure.
Adam Wright
Adam Wright: one word: method_missing
Sarah Mei
Or is that two words? ;)
Sarah Mei
@Adam: You named three message-passing languages in which you can send messages without corresponding methods, and you named one non-message language where you can't. How does that disagree with what I said?
Chuck
Both Chuck and Sarah Mei have separately cited method_missing as evidence in answering this question. Why is method_missing so important in this picture?
lorz
Because it's not "message passing" vs "method calling". I can construct runtime method calls in C++, and in C#. We're talking "late binding" vs "early binding" in these comments (or perhaps "dynamic dispatch"); I don't think it's that helpful to the OP to really get into the minutiae.
Adam Wright
+1  A: 

Whatever object contains this code is sending the message — presumably main. Let's look at it with more explicit objects and normal message-passing.

class Person
  attr_accessor :first_name, :last_name
  def initialize(first_name, last_name)
    @first_name, @last_name = first_name, last_name
  end
  def marry(other)
    self.last_name = other.last_name
  end
end

bob = Person.new('Bob', 'Smith')
patty = Person.new('Patricia', 'Johnson')

patty.marry bob

In the last line of this code, main is sending marry to patty, and patty in turn sends herself last_name= and sends bob last_name.

Chuck
How do we know "main is sending marry to patty" rather than "patty is invoking marry on herself"?
lorz
Patty is performing the marry method — in response to our message. We could delete the marry method and implement method_missing and we'd still see and be able to respond to the message even though there's no longer a marry method to invoke.
Chuck
Sorry I'm slow to understand. I'm still not getting why your last point demonstrates that main is the origin of the message rather than patty.
lorz
The fact that the sender is the one that sends the message is kind of an a priori fact of the language. Smalltalk was conceived as a bunch of autonomous objects communicating with each other by messages, and Ruby carries on this philosophy. If you'd like a demonstration that there are two different senders here, call `private :marry`. patty will still be able to tell herself to marry, but your message will be rejected. Or do Array.new.<<(self) and you'll see that the self that gets added to the array is the sending object, not the array itself.
Chuck
"private :marry" produces "undefined method 'marry' for class Object". I'm not sure what this shows. But "puts Array.new.<<(self)" produces "main" and, yes, this demonstrates that main is the context directly external to patty. If we accept that the message is being sent to patty from the surrounding context, then it must be coming from "main".
lorz
+1  A: 

I can see where you're getting confused, but the issue is largely semantic. Your argument is that the send method should really be receive, since k is receiving a message (i.e., k.receive :hello). In plain English, you read k.send :hello as "k sends the message 'hello' (to whom?)", rather than "k is sent the messsage 'hello'".

One could rename the method "receive", but that's also a bit of a misnomer, because k might not receive the message -- k may not respond to the message, k may choose to ignore it, or k may choose to pass it on to another object. In Ruby (and Smalltalk, which influenced Ruby), methods are more like requests to do something, rather than commands to do it.

mipadi
Yes, you've understood my semantic confusion. But I don't understand your point - "k might not receive the message -- k may not respond to the message, k may choose to ignore it, or k may choose to pass it on to another object" How is it possible for k to ignore the message?
lorz
In Smalltalk, the exact same method is called perform:, which I think is a much better name for it.
Chuck
@ lorz: Several reasons: k might not implement the method 'hello', or it may choose to do nothing in its implementation; or it can just pass the message on to another object. My choice of "ignore" might be poor (since in, e.g., Java, you could have a method implementation that simply does nothing).@ Chuck: I agree. I think the Cocoa framework uses the name performSelector:, too.
mipadi
@ lorz: To elaborate, when you call a method on an object in Ruby, a "message" is sent to the object (the message being the name of the method). If that method is not implemented, a method called "method_missing" is then called, again with the name of the original message. Objects can choose to do something in method_missing (Rails uses this to a fair extent, for example), or it may discard the message, or it may do nothing (thus raising an exception by default), or it may pass the message to another object.
mipadi
@mipadi - Thanks. That clears up the receiving part of the chain. What I'm still not clear about, though, is how we identify the sender of the message. In Chuck's example, he says "main is sending marry to patty". What is "main" and how do we know "main" is the origin of the message?
lorz
In a call like "patty.marry bob", patty is sent the message marry; the sender is, well, whatever wrote that piece of code, I guess. "sending a message" is basically the same as "calling a method" in Java, so in the case of, e.g., patty.marry bob, the "thing" that sends the message is the same as the "thing" that calls the method in a line like Java's "patty.marry(bob)".
mipadi