Ruby send vs __send__
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).
Ruby `send` vs `call` method
To begin with, send
and call
are two very different methods.
In ruby, the concept of object orientation takes its roots from Smalltalk. Basically, when you call a method, you are sending that object a message. So, it makes sense that when you want to dynamically call a method on an object, the method you call is send
. This method has existed in ruby since at least 1.8.7.
In ruby, we also have a concept of "blocks". Blocks are the do...end
things attached to the end of method calls. Blocks can be traditionally yield
ed to; or, it is entirely possible to create an object out of a block (a Proc
), and pass that around. In order to execute the block, you can call call
on the block.
call
has never been defined on Object
, whereas send
is defined on everything.
(note: for some reason, call
doesn't seem to have documentation in the 2.3.0 documentation; however, it still exists and does the same thing from 2.2.0, so I linked that one instead.)
What is the difference between Ruby's send and public_send methods?
Unlike send, public_send calls public methods only.
Source
Example:
class Klass
private
def private_method
puts "Hello"
end
end
k = Klass.new
k.send(:private_method)
# => "Hello"
k.public_send(:private_method)
# => `public_send': private method `private_method' called for #<Klass:0x007f5fd7159a80> (NoMethodError)
You may want to prefer #public_send
over #send
so as not to circumvent private/protected visibility.
What is the point of using send instead of a normal method call?
It can come in handy if you don't know in advance the name of the method, when you're doing metaprogramming for example, you can have the name of the method in a variable and pass it to the send
method.
It can also be used to call private methods, although this particular usage is not considered to be a good practice by most Ruby developers.
class Test
private
def my_private_method
puts "Yay"
end
end
t = Test.new
t.my_private_method # Error
t.send :my_private_method #Ok
You can use public_send
though to only be able to call public methods.
What does send() do in Ruby?
send
sends a message to an object instance and its ancestors in class hierarchy until some method reacts (because its name matches the first argument).
Practically speaking, those lines are equivalent:
1.send '+', 2
1.+(2)
1 + 2
Note that send
bypasses visibility checks, so that you can call private methods, too (useful for unit testing).
If there is really no variable before send, that means that the global Object is used:
send :to_s # "main"
send :class # Object
What is the send() method used for?
The Ruby implementation for the send
method, which is used to send a method message to an object, works like this:
class Car
def start
puts "vroom"
end
private
def engine_temp
puts "Just Right"
end
end
@car = Car.new
@car.start # output: vroom
@car.send(:start) # output: vroom
That's the basics, an additional piece of important information is that send will allow you you send in messages to PRIVATE methods, not just public ones.
@car.engine_temp # This doesn't work, it will raise an exception
@car.send(:engine_temp) # output: Just Right
As for what your specific send call will do, more than likely there is a def method_missing
in the Performer
class that is setup to catch that and perform some action.
send method in Ruby
First of all, things like []
(array index) and []=
are just methods in Ruby. x
is an Array
, and arrays have a []=
method, which accepts two arguments, an index and a value to set.
Using send
lets you pass an arbitrary "message" (method call) to object, with arbitrary parameters.
You could call x.send :sort
, for example, to send the "sort" message to the array. Sort doesn't need any parameters, though, so we don't have to pass anything extra to it.
x#[]=
, on the other hand, accepts two arguments. Its method can be thought of to look like this:
def []=(index, value)
self.set_value_at_index(index, value)
end
So, we can just invoke it with send :[]=, 0, 2
, which is just like calling x[0] = 2
. Neat, huh?
When can I safely call send method on objects in Ruby?
TLDR;
Calling send is fine, it's inside your class.
Full Explanation
Alex, Here is what I have always thought about this tactic. I believe that this is well inline with the community.
The Ruby Docs say this about send:
Invokes the method identified by symbol, passing it any arguments specified. You can use
__send__
if the name send clashes with an existing method in obj.
This is a public method accessible to anyone in the world. That means anyone using your code can call private functions whenever they want!
Thus... you shouldn't really think in terms of public and private functions as you would in other languages. I would argue you change your definitions a little bit.
Public: Well-tested, robust, error-checked functions which are recommended for use by the world.
Private: Helper functions which may accept invalid input and break things.
I don't have some big rationale for this, just an overall impression about how these concepts work in Ruby.
For your specific problem its important to remember that you are the one coding this up, and I assume that your code is within a class you created. In that case, I use send
all the time! It's shorted than public_send
and I know exactly what I'm calling!
You will want to document it well enough so that anyone coming behind you will know what to be careful of.
Usage of `Object#send` method as a best practice
There's reasons to use this, and there's reasons to avoid it. This trivial example is a case of an anti-pattern because it's a fixed array and it would be more concise to write:
create
update
pause
Where you have a case for using it is when the array isn't necessarily static, where there might be modifications, especially when used in the context of a DSL.
Rails employs this for the before_validation
handler chain, for example, where it has a list of Symbol references or Proc functions to call:
before_validation :check_sanity
before_validation lambda { do_something(1) }
Related Topics
Rails 3.2 'Link_To' (In Email) with 'Method: :Put' Still Producing Get Request
How to Match Full Words and Not Substrings in Ruby
When Did "Assigned But Unused" Become a Warning for Ruby
Hacking Activerecord: Add Global Named Scope
The Number of Trailing Zeros in a Factorial of a Given Number - Ruby
Why Does Ruby's String#To_I Sometimes Return 0 When the String Contains a Number
Nokogiri - Error: Failed to Build Gem Native Extension
Rails Active Admin CSS Conflicting with Twitter Bootstrap CSS
Selenium-Webdriver Ruby --> How to Wait for Images to Be Fully Loaded After Click
What Are <-- Ruby Strings Called? and How to Insert Variables in Them
Setting Path for Whenever in Cron So It Can Find Ruby
Handling a JavaScript Popup Occurring on a Keyup Event
How to Get Indexes of All Occurrences of a Pattern in a String
Ruby Regex Error: Incompatible Encoding Regexp Match (Ascii-8Bit Regexp with Utf-8 String)