Reputation:
I understand the concept of some_instance.send
but I'm trying to figure out why you can call this both ways. The Ruby Koans imply that there is some reason beyond providing lots of different ways to do the same thing. Here are the two examples of usage:
class Foo
def bar?
true
end
end
foo = Foo.new
foo.send(:bar?)
foo.__send__(:bar?)
Anyone have any idea about this?
Upvotes: 184
Views: 27214
Reputation: 869
The main difference between send, __send__
, and public_send is as follow.
__send__
are technaically same as used to call Object's method, but the main difference is you can override the send method without any warning and when you override __send__
then there is a warning messagewarning: redefining
__send__
may cause serious problems
This is because to avoid conflicts, specially in gems or libraries when the context where it will be used is unknown, always use __send__
instead of send.
__send__
) and public_send is that send / __send__
can call an object’s private methods, and public_send can’t.class Foo
def __send__(*args, &block)
"__send__"
end
def send(*args)
"send"
end
def bar
"bar"
end
private
def private_bar
"private_bar"
end
end
Foo.new.bar #=> "bar"
Foo.new.private_bar #=> NoMethodError(private method 'private_bar' called for #Foo)
Foo.new.send(:bar) #=> "send"
Foo.new.__send__(:bar) #=> "__send__"
Foo.new.public_send(:bar) #=> "bar"
Foo.new.send(:private_bar) #=> "send"
Foo.new.__send__(:private_bar) #=> "__send__"
Foo.new.public_send(:private_bar) #=> NoMethodError(private method 'private_bar' called for #Foo)
At the end try to use public_send to avoid direct call to private method instead of using __send__ or send.
Upvotes: 1
Reputation: 12578
Apart from what others already told you, and what boils down to saying that send
and __send__
are two aliases of the same method, you might be interested in the third, somwhat different possibility, which is public_send
. Example:
A, B, C = Module.new, Module.new, Module.new
B.include A #=> error -- private method
B.send :include, A #=> bypasses the method's privacy
C.public_send :include, A #=> does not bypass privacy
Update: Since Ruby 2.1, Module#include
and Module#extend
methods become public, so the above example would not work anymore.
Upvotes: 6
Reputation: 81450
__send__
exists so it can't be over-written by accident.
As for why send
exists: I can't speak for anyone else, but object.send(:method_name, *parameters)
looks nicer than object.__send__(:method_name, *parameters)
, so I use send
unless I need to use __send__
.
Upvotes: 12
Reputation: 5133
If you really need send
to behave like it would normally do, you should use __send__
, because it won't (it shouldn't) be overriden. Using __send__
is especially useful in metaprogramming, when you don't know what methods the class being manipulated defines. It could have overriden send
.
Watch:
class Foo
def bar?
true
end
def send(*args)
false
end
end
foo = Foo.new
foo.send(:bar?)
# => false
foo.__send__(:bar?)
# => true
If you override __send__
, Ruby will emit a warning:
warning: redefining `__send__' may cause serious problems
Some cases where it would be useful to override send
would be where that name is appropriate, like message passing, socket classes, etc.
Upvotes: 37
Reputation: 370102
Some classes (for example the standard library's socket class) define their own send
method which has nothing to do with Object#send
. So if you want to work with objects of any class, you need to use __send__
to be on the safe side.
Now that leaves the question, why there is send
and not just __send__
. If there were only __send__
the name send
could be used by other classes without any confusion. The reason for that is that send
existed first and only later it was realized that the name send
might also usefully be used in other contexts, so __send__
was added (that's the same thing that happened with id
and object_id
by the way).
Upvotes: 278