Ruby Send VS _Send_

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



Leave a reply



Submit