WCGPR0
WCGPR0

Reputation: 789

How does this code with send :[] work?

The following code generates an output of 9. I understand send is simply calling the method :[], but am confused how the parameters work.

 x = [1,2,3]
 x.send :[]=,0,4                             #why is x now [4,2,3]
 x[0] + x.[](1) + x.send(:[],2)              # 4 + 2 + 3

How do line 2 and line 3 work?

Upvotes: 2

Views: 86

Answers (3)

Petr Skocik
Petr Skocik

Reputation: 60068

x.send(:[]=, 0, 4)

is the same* as

x.[]=(0, 4) 

which has the syntactic sugar of

x[0] = 4

which should be familiar from other languages. Parentheses are, of course, optional.

The .send or .public_send variety has the advantage that the method to invoke doesn't have to be hardcoded—it can come from a variable.

All this is congruent with ruby's paradigm of object orientedness: objects communicate with each other by sending messages, and the messages trigger code execution.


*almost, #send will invoke private methods too

Upvotes: 4

David Grayson
David Grayson

Reputation: 87406

Line 2 is

x.send :[]=,0,4

That is basically a fancy way of writing this:

x[0] = 4

(Calling send allows you to call private methods though, and that is one difference between the two syntaxes. Also, an object could conceivably override the send method, which would break the first syntax.)

So line 2 has the effect of writing 4 into the first spot in the array.

Now on line 3, we see that we are adding up three things. Here is a list of the things we are adding:

  • x[0] - the first element
  • x.[](1) - another syntax for accessing elements, which accesses the second element. This syntax is a traditional method call, where the name of the method happens to be [].
  • x.send(:[], 2) - This shows another feature of Ruby, which is the send method. It accesses the third element.

So the result will be 9, because the third line adds the first, second, and third elements of the array.

These examples appear to illustrate an interesting point about the design of the Ruby language. Specifically, array accesses are implemented as method calls. The preferred syntax for writing to an array is x[0] = 4 and the preferred syntax for reading is x[0], because that syntax is familiar to programmers from many different languages. However, reading and writing from arrays is actually implemented using method calls under the hood, and that's why it is possible to use some other syntaxes that look more like a traditional method call.

A traditional method call looks like this: object.foo(arg1, arg2, arg3, ...).

The send thing shown above is a useful feature of Ruby that allows you to specify which method you are calling using a symbol, instead of forcing you to type the exact name. It also lets you call private methods.

Upvotes: 3

Yu Hao
Yu Hao

Reputation: 122383

Object#send provides another way to invoke a method.

x.send :[]=,0,4  

is saying, invoke []= method on x, and pass the argument 0, 4, it's equivalent to:

x[0] = 4

The name send is because in Ruby, methods are invoked by sending a message to an object. The message contains the method's name, along with parameters the method may need. This idea comes from SmallTalk.

Upvotes: 4

Related Questions