Ruby 'send' Vs 'Call' Method

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 yielded 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 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.

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).

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

Ruby method call, element.send(), throws ArgumentError

Calling the method this way works.

value = method(element)

What is wrong with the element.send(method) syntax?

In your example, element is an integer, and method is a symbol, e.g. 1 and :method.

So value = method(element) is equivalent to:

value = method(1)

whereas value = element.send(method) is equivalent to:

value = 1.send(:method)

which is basically:

value = 1.method

It should be obvious that method(1) and 1.method is not the same.

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.



Related Topics



Leave a reply



Submit